Let’s start by reading your data:

# Import libraries:
# Load libraries
# Note: commented-out libraries are experimental libraries for other functions not used in this final analysis file
library(limma)
#library(DESeq2)
library(edgeR)
#library(Rsubread)
library(sns)
Package: sns, Version: 1.1.2
Metropolis-Hastings MCMC using Stochastic Newton Sampler
Scientific Computing Group, Sentrana Inc. &
Imperial College London
#library(Glimma)
library(data.table)
Registered S3 method overwritten by 'data.table':
  method           from
  print.data.table     
data.table 1.14.2 using 20 threads (see ?getDTthreads).  Latest news: r-datatable.com
library(tidyr)
#library(magrittr)
library(tidyverse)
Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
── Attaching packages ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse 1.3.1 ──
✔ ggplot2 3.3.6     ✔ dplyr   1.0.9
✔ tibble  3.1.7     ✔ stringr 1.4.0
✔ readr   2.1.2     ✔ forcats 0.5.2
✔ purrr   0.3.4     
── Conflicts ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::between()   masks data.table::between()
✖ dplyr::filter()    masks stats::filter()
✖ dplyr::first()     masks data.table::first()
✖ dplyr::lag()       masks stats::lag()
✖ dplyr::last()      masks data.table::last()
✖ purrr::transpose() masks data.table::transpose()
#library(sjPlot)
#library(sjlabelled)
library(sjmisc)
Learn more about sjmisc with 'browseVignettes("sjmisc")'.

Attaching package: ‘sjmisc’

The following object is masked from ‘package:purrr’:

    is_empty

The following object is masked from ‘package:tibble’:

    add_case

The following object is masked from ‘package:tidyr’:

    replace_na
library(ggplot2)
#library(effects)
#library(broom)
#library(GGally)
#library(emmeans)
#library(ggpubr)
#theme_set(theme_pubr())
library(corncob)
library(phyloseq)

# Import data:
otus <- read.csv("gut_full.csv", check.names=F)
taxa <- read.csv("taxa.csv",sep='\t')
otus$sex <- factor(otus$sex) #factorize sex
otus$vendor_dashboard <- factor(otus$vendor_dashboard)
otus$bowel <- factor(as.numeric(factor(otus$bowel, levels = c(1,2,3,4), labels = c(1,2,3,4))))
otus <- otus[ which(otus$vendor_dashboard == "Second Genome" | otus$vendor_dashboard == "research-microbiome"),] # keep only data where vendor is explicit
otus$vendor_dashboard = str_replace_all(otus$vendor_dashboard,"research-microbiome","DNA Genotek")
otus$vendor_dashboard <- factor(otus$vendor_dashboard) # factorize vendor
#otus[ which(otus$vendor_dashboard == "Second Genome"),]
otus <- within(otus, bowel <- relevel(bowel, ref = 3))

# Pre-processing and checking validity of data
# Algorithms provided by Christian Diener, PhD:
dat <- otus
otus <- otus[!duplicated(otus$public_client_id), ]
genus_cols <- grepl("taxa_", names(otus))
rownames(otus) <- otus$public_client_id
sdata <- otus[, !genus_cols]
bowel <- paste0(sdata['bowel'])
table(sdata['bowel'])

   3    1    2    4 
1796   83  769   41 
otus <- as.matrix(otus[, genus_cols])
colnames(otus) <- gsub("taxa_", "", colnames(otus))
tax_matrix <- as.matrix(taxa[, 2:ncol(taxa)])
rownames(tax_matrix) <- taxa[, 1]
as.data.frame(otus)

Now we convert it to fit in a phyloseq object. We need to fulfill the following rules:

  1. The OTU table is a matrix with rows being samples and each column being a taxon.
  2. The taxonomy table must be a matrix with rows being taxa and columns being ranks.
  3. The sample data must be data frame with rows being samples.

To double check if everything works let’s do some validity checks:

stopifnot(all(rownames(otus) %in% rownames(sdata)))
stopifnot(nrow(otus) == nrow(sdata))
print("sample names match")
[1] "sample names match"
stopifnot(all(colnames(otus) %in% rownames(tax_matrix)))
stopifnot(ncol(otus) == nrow(tax_matrix))
stopifnot(!anyDuplicated(tax_matrix))
print("taxa look okay")
[1] "taxa look okay"
stopifnot(!anyDuplicated(sdata))
print("sample data looks okay")
[1] "sample data looks okay"

If that passes we can go ahead and build our phyloseq object.

ps <- phyloseq(
  otu_table(otus, taxa_are_rows = FALSE),
  tax_table(tax_matrix),
  sample_data(sdata)
)

ps
phyloseq-class experiment-level object
otu_table()   OTU Table:         [ 68 taxa and 2689 samples ]
sample_data() Sample Data:       [ 2689 samples by 7 sample variables ]
tax_table()   Taxonomy Table:    [ 68 taxa by 6 taxonomic ranks ]
names(sample_data(ps))
[1] "public_client_id" "sex"              "age"              "BMI_CALC"         "vendor_dashboard" "bowel"            "eGFR"            
bowel <- sample_data(ps)$bowel
#Differential Test
dv_analysis <- differentialTest(formula = ~ bowel + sex + age + BMI_CALC + vendor_dashboard + eGFR,
                                 phi.formula = ~ 1,
                                 formula_null = ~ sex + age + BMI_CALC + vendor_dashboard + eGFR,
                                 phi.formula_null = ~ 1,
                                 data = ps,
                                 test = "LRT", boot = FALSE,
                                 full_output = TRUE,
                                 fdr_cutoff = 0.05)
#See the significant taxa from the computation:
dv_analysis$significant_taxa
 [1] "Bacteria.Actinobacteria.Actinobacteria.Bifidobacteriales.Bifidobacteriaceae.Bifidobacterium"    "Bacteria.Actinobacteria.Coriobacteriia.Coriobacteriales.Coriobacteriaceae.Collinsella"         
 [3] "Bacteria.Actinobacteria.Coriobacteriia.Coriobacteriales.Eggerthellaceae.Adlercreutzia"          "Bacteria.Bacteroidetes.Bacteroidia.Bacteroidales.Bacteroidaceae.Bacteroides"                   
 [5] "Bacteria.Bacteroidetes.Bacteroidia.Bacteroidales.Marinifilaceae.Odoribacter"                    "Bacteria.Bacteroidetes.Bacteroidia.Bacteroidales.Rikenellaceae.Alistipes"                      
 [7] "Bacteria.Bacteroidetes.Bacteroidia.Bacteroidales.Tannerellaceae.Parabacteroides"                "Bacteria.Firmicutes.Bacilli.Lactobacillales.Streptococcaceae.Streptococcus"                    
 [9] "Bacteria.Firmicutes.Clostridia.Clostridiales.Christensenellaceae.Christensenellaceae_R-7_group" "Bacteria.Firmicutes.Clostridia.Clostridiales.Christensenellaceae.nan"                          
[11] "Bacteria.Firmicutes.Clostridia.Clostridiales.Clostridiales_vadinBB60_group.nan"                 "Bacteria.Firmicutes.Clostridia.Clostridiales.Family_XIII.Family_XIII_AD3011_group"             
[13] "Bacteria.Firmicutes.Clostridia.Clostridiales.Family_XIII.Family_XIII_UCG-001"                   "Bacteria.Firmicutes.Clostridia.Clostridiales.Family_XIII.nan"                                  
[15] "Bacteria.Firmicutes.Clostridia.Clostridiales.Lachnospiraceae.Agathobacter"                      "Bacteria.Firmicutes.Clostridia.Clostridiales.Lachnospiraceae.Blautia"                          
[17] "Bacteria.Firmicutes.Clostridia.Clostridiales.Lachnospiraceae.Lachnoclostridium"                 "Bacteria.Firmicutes.Clostridia.Clostridiales.Lachnospiraceae.Lachnospira"                      
[19] "Bacteria.Firmicutes.Clostridia.Clostridiales.Lachnospiraceae.Lachnospiraceae_NK4A136_group"     "Bacteria.Firmicutes.Clostridia.Clostridiales.Lachnospiraceae.Lachnospiraceae_UCG-004"          
[21] "Bacteria.Firmicutes.Clostridia.Clostridiales.Lachnospiraceae.Marvinbryantia"                    "Bacteria.Firmicutes.Clostridia.Clostridiales.Lachnospiraceae.nan"                              
[23] "Bacteria.Firmicutes.Clostridia.Clostridiales.Peptostreptococcaceae.Romboutsia"                  "Bacteria.Firmicutes.Clostridia.Clostridiales.Ruminococcaceae.Anaerotruncus"                    
[25] "Bacteria.Firmicutes.Clostridia.Clostridiales.Ruminococcaceae.Butyricicoccus"                    "Bacteria.Firmicutes.Clostridia.Clostridiales.Ruminococcaceae.Candidatus_Soleaferrea"           
[27] "Bacteria.Firmicutes.Clostridia.Clostridiales.Ruminococcaceae.DTU089"                            "Bacteria.Firmicutes.Clostridia.Clostridiales.Ruminococcaceae.Faecalibacterium"                 
[29] "Bacteria.Firmicutes.Clostridia.Clostridiales.Ruminococcaceae.GCA-900066225"                     "Bacteria.Firmicutes.Clostridia.Clostridiales.Ruminococcaceae.Intestinimonas"                   
[31] "Bacteria.Firmicutes.Clostridia.Clostridiales.Ruminococcaceae.Negativibacillus"                  "Bacteria.Firmicutes.Clostridia.Clostridiales.Ruminococcaceae.Oscillibacter"                    
[33] "Bacteria.Firmicutes.Clostridia.Clostridiales.Ruminococcaceae.Ruminiclostridium_5"               "Bacteria.Firmicutes.Clostridia.Clostridiales.Ruminococcaceae.Ruminiclostridium_9"              
[35] "Bacteria.Firmicutes.Clostridia.Clostridiales.Ruminococcaceae.Ruminococcaceae_NK4A214_group"     "Bacteria.Firmicutes.Clostridia.Clostridiales.Ruminococcaceae.Ruminococcaceae_UCG-002"          
[37] "Bacteria.Firmicutes.Clostridia.Clostridiales.Ruminococcaceae.Ruminococcaceae_UCG-004"           "Bacteria.Firmicutes.Clostridia.Clostridiales.Ruminococcaceae.Ruminococcaceae_UCG-005"          
[39] "Bacteria.Firmicutes.Clostridia.Clostridiales.Ruminococcaceae.Ruminococcaceae_UCG-013"           "Bacteria.Firmicutes.Clostridia.Clostridiales.Ruminococcaceae.Ruminococcus_1"                   
[41] "Bacteria.Firmicutes.Clostridia.Clostridiales.Ruminococcaceae.Ruminococcus_2"                    "Bacteria.Firmicutes.Clostridia.Clostridiales.Ruminococcaceae.Subdoligranulum"                  
[43] "Bacteria.Firmicutes.Clostridia.Clostridiales.Ruminococcaceae.UBA1819"                           "Bacteria.Firmicutes.Clostridia.Clostridiales.Ruminococcaceae.nan"                              
[45] "Bacteria.Firmicutes.Erysipelotrichia.Erysipelotrichales.Erysipelotrichaceae.Holdemania"         "Bacteria.Firmicutes.Erysipelotrichia.Erysipelotrichales.Erysipelotrichaceae.nan"               
[47] "Bacteria.Verrucomicrobia.Verrucomicrobiae.Verrucomicrobiales.Akkermansiaceae.Akkermansia"      
saveRDS(dv_analysis, "corncob_all3.rds")
#Load the .rds file as "dv_analysis" to continue from already computed dv_analysis file from before.
#This way you don't need to run the computation all over again each time you want to run the code from here below:
library(DataCombine)
taxa<-dv_analysis$all_models
dv_analysis$significant_taxa
 [1] "Bacteria.Actinobacteria.Actinobacteria.Bifidobacteriales.Bifidobacteriaceae.Bifidobacterium"   
 [2] "Bacteria.Actinobacteria.Coriobacteriia.Coriobacteriales.Coriobacteriaceae.Collinsella"         
 [3] "Bacteria.Actinobacteria.Coriobacteriia.Coriobacteriales.Eggerthellaceae.Adlercreutzia"         
 [4] "Bacteria.Bacteroidetes.Bacteroidia.Bacteroidales.Bacteroidaceae.Bacteroides"                   
 [5] "Bacteria.Bacteroidetes.Bacteroidia.Bacteroidales.Marinifilaceae.Odoribacter"                   
 [6] "Bacteria.Bacteroidetes.Bacteroidia.Bacteroidales.Rikenellaceae.Alistipes"                      
 [7] "Bacteria.Bacteroidetes.Bacteroidia.Bacteroidales.Tannerellaceae.Parabacteroides"               
 [8] "Bacteria.Firmicutes.Bacilli.Lactobacillales.Streptococcaceae.Streptococcus"                    
 [9] "Bacteria.Firmicutes.Clostridia.Clostridiales.Christensenellaceae.Christensenellaceae_R-7_group"
[10] "Bacteria.Firmicutes.Clostridia.Clostridiales.Christensenellaceae.nan"                          
[11] "Bacteria.Firmicutes.Clostridia.Clostridiales.Clostridiales_vadinBB60_group.nan"                
[12] "Bacteria.Firmicutes.Clostridia.Clostridiales.Family_XIII.Family_XIII_AD3011_group"             
[13] "Bacteria.Firmicutes.Clostridia.Clostridiales.Family_XIII.Family_XIII_UCG-001"                  
[14] "Bacteria.Firmicutes.Clostridia.Clostridiales.Family_XIII.nan"                                  
[15] "Bacteria.Firmicutes.Clostridia.Clostridiales.Lachnospiraceae.Agathobacter"                     
[16] "Bacteria.Firmicutes.Clostridia.Clostridiales.Lachnospiraceae.Blautia"                          
[17] "Bacteria.Firmicutes.Clostridia.Clostridiales.Lachnospiraceae.Lachnoclostridium"                
[18] "Bacteria.Firmicutes.Clostridia.Clostridiales.Lachnospiraceae.Lachnospira"                      
[19] "Bacteria.Firmicutes.Clostridia.Clostridiales.Lachnospiraceae.Lachnospiraceae_NK4A136_group"    
[20] "Bacteria.Firmicutes.Clostridia.Clostridiales.Lachnospiraceae.Lachnospiraceae_UCG-004"          
[21] "Bacteria.Firmicutes.Clostridia.Clostridiales.Lachnospiraceae.Marvinbryantia"                   
[22] "Bacteria.Firmicutes.Clostridia.Clostridiales.Lachnospiraceae.nan"                              
[23] "Bacteria.Firmicutes.Clostridia.Clostridiales.Peptostreptococcaceae.Romboutsia"                 
[24] "Bacteria.Firmicutes.Clostridia.Clostridiales.Ruminococcaceae.Anaerotruncus"                    
[25] "Bacteria.Firmicutes.Clostridia.Clostridiales.Ruminococcaceae.Butyricicoccus"                   
[26] "Bacteria.Firmicutes.Clostridia.Clostridiales.Ruminococcaceae.Candidatus_Soleaferrea"           
[27] "Bacteria.Firmicutes.Clostridia.Clostridiales.Ruminococcaceae.DTU089"                           
[28] "Bacteria.Firmicutes.Clostridia.Clostridiales.Ruminococcaceae.Faecalibacterium"                 
[29] "Bacteria.Firmicutes.Clostridia.Clostridiales.Ruminococcaceae.GCA-900066225"                    
[30] "Bacteria.Firmicutes.Clostridia.Clostridiales.Ruminococcaceae.Intestinimonas"                   
[31] "Bacteria.Firmicutes.Clostridia.Clostridiales.Ruminococcaceae.Negativibacillus"                 
[32] "Bacteria.Firmicutes.Clostridia.Clostridiales.Ruminococcaceae.Oscillibacter"                    
[33] "Bacteria.Firmicutes.Clostridia.Clostridiales.Ruminococcaceae.Ruminiclostridium_5"              
[34] "Bacteria.Firmicutes.Clostridia.Clostridiales.Ruminococcaceae.Ruminiclostridium_9"              
[35] "Bacteria.Firmicutes.Clostridia.Clostridiales.Ruminococcaceae.Ruminococcaceae_NK4A214_group"    
[36] "Bacteria.Firmicutes.Clostridia.Clostridiales.Ruminococcaceae.Ruminococcaceae_UCG-002"          
[37] "Bacteria.Firmicutes.Clostridia.Clostridiales.Ruminococcaceae.Ruminococcaceae_UCG-004"          
[38] "Bacteria.Firmicutes.Clostridia.Clostridiales.Ruminococcaceae.Ruminococcaceae_UCG-005"          
[39] "Bacteria.Firmicutes.Clostridia.Clostridiales.Ruminococcaceae.Ruminococcaceae_UCG-013"          
[40] "Bacteria.Firmicutes.Clostridia.Clostridiales.Ruminococcaceae.Ruminococcus_1"                   
[41] "Bacteria.Firmicutes.Clostridia.Clostridiales.Ruminococcaceae.Ruminococcus_2"                   
[42] "Bacteria.Firmicutes.Clostridia.Clostridiales.Ruminococcaceae.Subdoligranulum"                  
[43] "Bacteria.Firmicutes.Clostridia.Clostridiales.Ruminococcaceae.UBA1819"                          
[44] "Bacteria.Firmicutes.Clostridia.Clostridiales.Ruminococcaceae.nan"                              
[45] "Bacteria.Firmicutes.Erysipelotrichia.Erysipelotrichales.Erysipelotrichaceae.Holdemania"        
[46] "Bacteria.Firmicutes.Erysipelotrichia.Erysipelotrichales.Erysipelotrichaceae.nan"               
[47] "Bacteria.Verrucomicrobia.Verrucomicrobiae.Verrucomicrobiales.Akkermansiaceae.Akkermansia"      
as.data.frame(dv_analysis$p_fdr)
taxa_p <- DropNA(as.data.frame(dv_analysis$p_fdr), Var = "dv_analysis$p_fdr")
0 rows dropped from the data frame because of missing values.
taxa_p[1]
[1] 0.02120539
taxa[[1]]$coefficients
                                     Estimate  Std. Error     t value     Pr(>|t|)
mu.(Intercept)                   -3.368074680 0.182186294 -18.4869816 6.486060e-72
mu.bowel1                         0.108766498 0.121122817   0.8979852 3.692741e-01
mu.bowel2                         0.136368966 0.046755183   2.9166599 3.567424e-03
mu.bowel4                        -0.212360465 0.178644229  -1.1887340 2.346497e-01
mu.sexW                          -0.212789194 0.048369795  -4.3992163 1.128862e-05
mu.age                           -0.016148200 0.001821779  -8.8639749 1.378229e-18
mu.BMI_CALC                      -0.003154924 0.003370311  -0.9360928 3.493098e-01
mu.vendor_dashboardSecond Genome  0.127694322 0.060993339   2.0935782 3.639137e-02
mu.eGFR                           0.001582766 0.001243639   1.2726892 2.032388e-01
phi.(Intercept)                  -2.808912916 0.043294681 -64.8789385 0.000000e+00
sample_data(arivale_phylo) 
Sample Data:        [3653 samples by 26 sample variables]:
#Tom's code:
#Rarefy genotek dataset to even depth
#rarefy even depth is a command in phyloseq
#rarefy for alpha diversity, but not for corncob
rarefied_genotek=rarefy_even_depth(arivale_phylo, sample.size = min(sample_sums(arivale_phylo)),
  rngseed = 111, replace = FALSE, trimOTUs = TRUE, verbose = TRUE)
`set.seed(111)` was used to initialize repeatable random subsampling.
Please record this for your records so others can reproduce.
Try `set.seed(111); .Random.seed` for the full vector
...
25984OTUs were removed because they are no longer 
present in any sample after random subsampling

...
richness <- estimate_richness(rarefied_genotek, measures=c("Shannon","Observed"))
#Refer to Christian (phytree?) on PD whole tree (phyloseq additional PD whole tree package, check it) and add it to richness column on df.
richness$public_client_id <-sample_data(rarefied_genotek)$public_client_id
#Refer to Christian (phytree?) on PD whole tree (phyloseq additional PD whole tree package, check it) and add it to richness column on df.

library(btools)
richness$Pielou <- richness$Shannon/richness$Observed

richness
hist(richness$Pielou,
     main = "Pielou's Evenness (Shannon/Observed ASV)",
     xlab = "Evenness",
     xlim = c(0,0.05),
     breaks = 200)


hist(richness$Shannon,
     main = "Shannon Diversity",
     xlab = "Diversity Index",
     xlim = c(0,6),
     breaks = 20)


hist(richness$Observed,
     main = "Observed ASVs",
     xlab = "ASVs",
     xlim = c(0,1000),
     breaks = 30)

library(tidyverse)
library(ggpmisc)
library(quantreg)
library(broom)
library(ggbeeswarm)
library(ggsignif)
library(gginnards)
library(ggpubr)
library(ggpmisc)
library(broom.mixed)
library(scales)
#library(nlme)

sam.n <- function(x){
  return(c(y = mean(x), label = length(x)))
}

combinations <- list(c("Constipation","Low Normal"),
                                 c("Constipation","High Normal"),
                                 c("Constipation","Diarrhea"),
                                 c("Low Normal","High Normal"),
                                 c("Low Normal","Diarrhea"),
                                 c("High Normal","Diarrhea"))
dat$bowel <- factor(dat$bowel, levels = c("Constipation", "Low Normal", "High Normal", "Diarrhea"), labels = c("Constipation", "Low Normal", "High Normal", "Diarrhea"))
library(compositions)
df <- read.csv("gut_full.csv", check.names=F)
colnames(df) = gsub("nan", "Unclassified", colnames(df))
comparisons = list(c("Constipation","High Normal"),c("Low Normal","High Normal"),c("Diarrhea","High Normal"))
df$bowel <- factor(df$bowel, levels = c(1,2,3,4), labels = c("Constipation", "Low Normal", "High Normal", "Diarrhea"))
df_otus <- dplyr::select(df, -c("public_client_id","bowel","vendor_dashboard","sex","age","BMI_CALC","eGFR"))

df_otus <- as.data.frame(clr(as.matrix(df_otus)))
df_select <- dplyr::select(df, c(1:7))
df_otus <- cbind(df_select,df_otus)
df <- df_otus
dat <- df_otus

library(ggrepel)
sam.n <- function(x){return(c(y = mean(x), label = length(x)))}

# ggplot2 plots
library(gplots)
library(ggrepel)
library(ggbreak)
library(sommer)

#BMF df
const <- c()
const_p <- c()
low <- c()
low_p <- c()
diarrhea <- c()
diarrhea_p <- c()
taxa_names <- c()
family_names <- c()
genus_names <- c()
likelihood <- c()
adj_p <- c()
names(dv_analysis$p) = gsub("nan", "Unclassified", names(dv_analysis$p))

#dv_analysis$all_models[order(dv_analysis$p[order(names(dv_analysis$p))])])
for (i in 1:length(dv_analysis$all_models[names(dv_analysis$p)])) {
  const_p[i] <- dv_analysis$all_models[[i]]$coefficients[2,4]
  const[i] <- dv_analysis$all_models[[i]]$coefficients[2,1]
  low_p[i] <- dv_analysis$all_models[[i]]$coefficients[3,4]
  low[i] <- dv_analysis$all_models[[i]]$coefficients[3,1]
  diarrhea_p[i] <- dv_analysis$all_models[[i]]$coefficients[4,4]
  diarrhea[i] <- dv_analysis$all_models[[i]]$coefficients[4,1]
  taxa_names[i] <- names(dv_analysis$p)[i]
  family_names[i] <- strsplit(taxa_names[i],'.',fixed=TRUE)[[1]][5]
  genus_names[i] <- strsplit(taxa_names[i],'.',fixed=TRUE)[[1]][6]
  likelihood[i] <- dv_analysis$all_models[[i]]$logL
  adj_p[i] <- dv_analysis$p_fdr[[i]]
}

genus_names[i] <- strsplit(taxa_names[i],'.',fixed=TRUE)[[1]][6]

p_df <- bind_cols(taxa_names,family_names,genus_names, likelihood, adj_p, const,const_p,low,low_p,diarrhea,diarrhea_p)
New names:
• `` -> `...1`
• `` -> `...2`
• `` -> `...3`
• `` -> `...4`
• `` -> `...5`
• `` -> `...6`
• `` -> `...7`
• `` -> `...8`
• `` -> `...9`
• `` -> `...10`
• `` -> `...11`
names(p_df) <- c("Genera","Family","Genus","LogL","Adj.P","Const.Beta","Const.P.Val","Low.Beta","Low.P.Val","Diarrhea.Beta","Diarrhea.P.Val")
p_df$Combined <- paste(p_df$Family,p_df$Genus)
ab <- colSums(df_otus[names(df_otus) %in% paste("taxa_",names(dv_analysis$p),sep="")])/colSums(!!df_otus[names(df_otus) %in% paste("taxa_",names(dv_analysis$p),sep="")])
p_df$Mean.Abundance <- ab[paste("taxa_",p_df$Genera,sep="")]

p_df$Const.Adj.P.Val <- p.adjust(const_p, method = "fdr", n = length(const_p))
p_df$Low.Adj.P.Val <- p.adjust(low_p, method = "fdr", n = length(low_p))
p_df$Diarrhea.Adj.P.Val <- p.adjust(diarrhea_p, method = "fdr", n = length(diarrhea_p))

p_df <- p_df[order(-p_df$Mean.Abundance),]


set <- subset(p_df[which(p_df$Adj.P < 0.05),], Genus != 'Unclassified')
set <- subset(set[order(-set$Mean.Abundance),], Genus != 'Unclassified')


abundant_list <- list()
abundant_genus <- list()
abundant <- paste("taxa_",set[order(-set$Mean.Abundance),]$Genera,sep="")
for (i in 1:68) {
  abundant_list[i] <- paste(strsplit(abundant[i],'.',fixed=TRUE)[[1]][5],strsplit(abundant[i],'.',fixed=TRUE)[[1]][6])
  abundant_genus[i] <- paste(strsplit(abundant[i],'.',fixed=TRUE)[[1]][6])
}

#top 10 most abundant non-unclassified hits
abundant_trunc <- set[match(abundant_list[!is.na(set$Combined[match(abundant_list,set$Combined)])],set$Combined),][which(set$Adj.P<0.05),]$Combined[1:10]
`%!in%` <- Negate(`%in%`)
t <- set[set$Combined %!in% abundant_trunc,]
#t[!is.na(t[order(t$Adj.P),]$Mean.Abundance),][order(t$Adj.P),]

span <- rbind(set[order(set[-order(set[!set$Combined %in% abundant_trunc,]$Adj.P),][which(set$Adj.P<0.05),]$Mean.Abundance %!in% abundant_trunc),][1:10,],
t[match('Akkermansiaceae Akkermansia',t$Combined),],
t[order(t$Const.Adj.P.Val),][1:9,])
span$Letters <- LETTERS[1:20]

p_df$Letters <- c(NA)
test <- rbind(span,p_df[p_df$Combined %!in% span$Combined,])
test <- test[!duplicated(test$Genera),]
#test[order(test[!duplicated(test),]$Letters),]
p_df <- test
p_df <- p_df[order(p_df$Adj.P),]
p_df <- p_df[order(-p_df$Mean.Abundance),]


model = y ~ x
df_num <- merge(richness, df_otus, by="public_client_id")
df_num <- within(df_num, bowel <- relevel(bowel, ref = 'High Normal'))
d1_plot <- lm(Pielou ~ bowel, data = df_num)
pval1 = summary(d1_plot)$coefficients[2,4]
r1 = summary(d1_plot)$adj.r.squared
pval1
[1] 0.001840045
r1
[1] 0.01204487
d1 <- ggplot(data = df_num, aes(x = factor(bowel, level = c("Constipation", "Low Normal", "High Normal", "Diarrhea"), labels = c("Constipation", "Low Normal", "High Normal", "Diarrhea")), y = Pielou, group = factor(bowel))) +
  scale_x_discrete(bquote(atop(~italic("adj R")^2~" = "~.(formatC(as.numeric(r1),3)),~italic("P value")~" = "~.(formatC(as.numeric(pval1),3)))))+
  geom_beeswarm(aes(color = bowel), cex = 0.5) +
  geom_boxplot(alpha=0) +
  ylim(0.005,0.05)+
  geom_smooth(method = "lm", formula = y ~ x, aes(group = 1)) +
  ggtitle(label = "C)\nPielou's Evenness vs BMF") +
  xlab("Bowel Movement Frequency (BMF)") +
  ylab("Pielou's Evenness") +
  scale_colour_discrete(name="BMF Category", limits = c("Constipation", "Low Normal", "High Normal", "Diarrhea"), labels=c("Constipation", "Low Normal", "High Normal", "Diarrhea")) +
  guides(colour = guide_legend(override.aes = list(size=7))) +
  theme(plot.title = element_text(size=10), legend.text = element_text(size = 10), legend.title = element_text(size = 10), axis.text.x = element_blank(), axis.title.y = element_text(size = 10))
d1
Warning: Removed 1 rows containing non-finite values (stat_boxplot).
Warning: Removed 1 rows containing non-finite values (stat_smooth).
Warning: Removed 1 rows containing missing values (position_beeswarm).

model = y ~ x
d2_plot <- lm(Shannon ~ bowel, data = df_num)
pval2 = summary(d2_plot)$coefficients[2,4]
r2 = summary(d2_plot)$adj.r.squared
pval2
[1] 0.00964909
r2
[1] 0.01384
d2 <- ggplot(data = df_num, aes(x = factor(bowel, level = c("Constipation", "Low Normal", "High Normal", "Diarrhea"), labels = c("Constipation", "Low Normal", "High Normal", "Diarrhea")), y = Shannon, group = bowel)) +
  scale_x_discrete(bquote(atop(~italic("adj R")^2~" = "~.(formatC(as.numeric(r2),3)),~italic("P value")~" = "~.(formatC(as.numeric(pval2),3)))))+
  geom_beeswarm(aes(color = factor(bowel)), cex = 0.5) +
  geom_boxplot(alpha=0) +
  geom_smooth(method = "lm", formula = y ~ x, aes(group = 1)) +
  ggtitle(label = "B)\nShannon Diversity vs BMF") +
  xlab("Bowel Movement Frequency (BMF)") +
  ylab("Shannon Diversity") +
  scale_colour_discrete(name="BMF Category", limits = c("Constipation", "Low Normal", "High Normal", "Diarrhea"), labels=c("Constipation", "Low Normal", "High Normal", "Diarrhea")) +
  guides(colour = guide_legend(override.aes = list(size=7))) +
  theme(plot.title = element_text(size=10), legend.text = element_text(size = 10), legend.title = element_text(size = 10), axis.text.x = element_blank(), axis.title.y = element_text(size = 10))
d2


model = y ~ x
d3_plot <- lm(Observed ~ bowel, data = df_num)
pval3 = summary(d3_plot)$coefficients[2,4]
r3 = summary(d3_plot)$adj.r.squared
pval3
[1] 5.448268e-05
r3
[1] 0.0208449
d3 <- ggplot(data = df_num, aes(x = factor(bowel, level = c("Constipation", "Low Normal", "High Normal", "Diarrhea"), labels = c("Constipation", "Low Normal", "High Normal", "Diarrhea")), y = Observed, group = bowel))+
  scale_x_discrete(bquote(atop(~italic("adj R")^2~" = "~.(formatC(as.numeric(r3),3)),~italic("P value")~" = "~.(formatC(as.numeric(pval3),3)))))+
  geom_beeswarm(aes(color = factor(bowel)), cex = 0.5) +
  geom_boxplot(alpha=0) +
  geom_smooth(method = "lm", formula = y ~ x, aes(group = 1)) +
  ggtitle(label = "A)\nObserved ASVs vs BMF") +
  xlab("Bowel Movement Frequency (BMF)") +
  ylab("Observed ASVs") +
  scale_colour_discrete(name="BMF Category", limits = c("Constipation", "Low Normal", "High Normal", "Diarrhea"), labels=c("Constipation", "Low Normal", "High Normal", "Diarrhea")) +
  guides(colour = guide_legend(override.aes = list(size=7))) +
  theme(plot.title = element_text(size=10), legend.text = element_text(size = 10), legend.title = element_text(size = 10), axis.text.x = element_blank(), axis.title.y = element_text(size = 10))
d3


PSO <- ggarrange(d3, d2, d1, legend = "top", align = "hv", common.legend = TRUE, widths = c(7,7,7), heights = c(20,20,20), nrow = 1, ncol = 3)+ theme(plot.margin = margin(0,0,0,0))
Warning: Removed 1 rows containing non-finite values (stat_boxplot).
Warning: Removed 1 rows containing non-finite values (stat_smooth).
Warning: Removed 1 rows containing missing values (position_beeswarm).
PSO
ggsave(
  "PSOvBMF.png",
  plot = PSO,
  device = NULL,
  path = NULL,
  scale = 1,
  width = NA,
  height = NA,
  units = c("in", "cm", "mm", "px"),
  dpi = 300,
  limitsize = TRUE,
  bg = NULL
)
Saving 7.29 x 4.51 in image


# Significant Genera Plot (plot 0)
plot0s <- ggplot(p_df, mapping = aes(x=Const.Beta,y = -log10(Const.P.Val), color = ifelse(p_df$Const.Adj.P.Val < 0.05,p_df$Genera,"- FDR Adj. P Value"),group = factor(ifelse(p_df$Const.Adj.P.Val < 0.05,p_df$Genera,"- FDR Adj. P Value"))))+
  geom_vline(xintercept = 0)+
  geom_point(size=1, aes(x = Const.Beta, y = -log10(Const.P.Val), group = factor(ifelse(p_df$Const.Adj.P.Val < 0.05,p_df$Letters,""))),position = position_dodge(width = 1)) +
  geom_label_repel(aes(x = Const.Beta, y = -log10(Const.P.Val), group = factor(ifelse(p_df$Const.Adj.P.Val < 0.05,p_df$Letters,""))), label.size = 0.1, label.padding = 0.1, box.padding = 0.5, min.segment.length = 0, point.size = NA, position = position_dodge(width = 1), size=2,label = factor(ifelse(p_df$Const.Adj.P.Val < 0.05,p_df$Letters,"")),color = "black", check_overlap = FALSE, max.overlaps = 127)+
 #ggtitle("Significant Genera") +
  xlab(bquote(beta~" Coefficient")) + 
  ylab(bquote("-log"[10]~"(P value)")) + 
  #scale_x_break(c(-0.6, -18)) +
  scale_x_continuous(name = bquote(atop(beta["BMF"]~" Coefficient",italic("Constipation"))), 
                     guide = guide_axis(n.dodge = 2), limits = c(-1.5,1.5)) +
  theme(text = 
          element_text(size = 14), 
        plot.title = element_text(vjust = 0.5), 
        #plot.subtitle = element_text(size=8, hjust = 0.5), 
        legend.title = element_blank(), 
        axis.title.y = element_text(size = 8),
        axis.title.x = element_text(size = 8),
              legend.text  = element_text(size = 3),
              legend.position = "top",
              legend.key.size = unit(0.1, "lines"))+
          guides(shape = guide_legend(override.aes = list(size = 1.5)),
               color = guide_legend(override.aes = list(size = 1.5), nrow = 25),
               fill=guide_legend(title=NULL),
               aspect.ratio = 0.95)
Warning: Ignoring unknown parameters: check_overlap
plot0s
Warning: Use of `p_df$Const.Adj.P.Val` is discouraged. Use `Const.Adj.P.Val` instead.
Warning: Use of `p_df$Letters` is discouraged. Use `Letters` instead.
Warning: Use of `p_df$Const.Adj.P.Val` is discouraged. Use `Const.Adj.P.Val` instead.
Warning: Use of `p_df$Genera` is discouraged. Use `Genera` instead.
Warning: Use of `p_df$Const.Adj.P.Val` is discouraged. Use `Const.Adj.P.Val` instead.
Warning: Use of `p_df$Letters` is discouraged. Use `Letters` instead.
Warning: position_dodge requires non-overlapping x intervals
Warning: position_dodge requires non-overlapping x intervals
Warning: Removed 13 rows containing missing values (geom_label_repel).

# Significant Genera Plot (plot 0)
plot0m <- ggplot(p_df, mapping = aes(x=Low.Beta,y = -log10(Low.P.Val), color = ifelse(p_df$Low.Adj.P.Val < 0.05,p_df$Genera,"- FDR Adj. P Value"),group = factor(ifelse(p_df$Low.Adj.P.Val < 0.05,p_df$Genera,"- FDR Adj. P Value"))))+
  geom_vline(xintercept = 0)+
  geom_point(size=1, aes(x = Low.Beta, y = -log10(Low.P.Val), group = factor(ifelse(p_df$Low.Adj.P.Val < 0.05,p_df$Letters,""))),position = position_dodge(width = 1)) +
  geom_label_repel(aes(x = Low.Beta, y = -log10(Low.P.Val), group = factor(ifelse(p_df$Low.Adj.P.Val < 0.05,p_df$Letters,""))), label.size = 0.1, label.padding = 0.1, box.padding = 0.5, min.segment.length = 0, point.size = NA, position = position_dodge(width = 1), size=2,label = factor(ifelse(p_df$Low.Adj.P.Val < 0.05,p_df$Letters,"")),color = "black", check_overlap = FALSE, max.overlaps = 127)+
 #ggtitle("Significant Genera") +
  xlab(bquote(beta~" Coefficient")) + 
  ylab(bquote("-log"[10]~"(P value)")) +
  #scale_x_break(c(-0.6, -18)) +
  scale_x_continuous(name = bquote(atop(beta["BMF"]~" Coefficient",italic("Low Normal"))), 
                     guide = guide_axis(n.dodge = 2)) +
  theme(text = 
          element_text(size = 14), 
        plot.title = element_text(vjust = 0.5), 
        #plot.subtitle = element_text(size=8, hjust = 0.5), 
        legend.title = element_blank(), 
        axis.title.y = element_text(size = 8),
        axis.title.x = element_text(size = 8),
              legend.text  = element_text(size = 3),
              legend.position = "top",
              legend.key.size = unit(0.1, "lines"))+
          guides(shape = guide_legend(override.aes = list(size = 1.5)),
               color = guide_legend(override.aes = list(size = 1.5), nrow = 25),
               fill=guide_legend(title=NULL),
               aspect.ratio = 0.95)
Warning: Ignoring unknown parameters: check_overlap
plot0m
Warning: Use of `p_df$Low.Adj.P.Val` is discouraged. Use `Low.Adj.P.Val` instead.
Warning: Use of `p_df$Letters` is discouraged. Use `Letters` instead.
Warning: Use of `p_df$Low.Adj.P.Val` is discouraged. Use `Low.Adj.P.Val` instead.
Warning: Use of `p_df$Genera` is discouraged. Use `Genera` instead.
Warning: Use of `p_df$Low.Adj.P.Val` is discouraged. Use `Low.Adj.P.Val` instead.
Warning: Use of `p_df$Letters` is discouraged. Use `Letters` instead.
Warning: position_dodge requires non-overlapping x intervals
Warning: position_dodge requires non-overlapping x intervals
Warning: Removed 27 rows containing missing values (geom_label_repel).

# Significant Genera Plot (plot 0)
plot0d <- ggplot(p_df, mapping = aes(x=Diarrhea.Beta,y = -log10(Diarrhea.P.Val), color = ifelse(p_df$Diarrhea.Adj.P.Val < 0.05,p_df$Genera,"- FDR Adj. P Value"),group = factor(ifelse(p_df$Diarrhea.Adj.P.Val < 0.05,p_df$Genera,"- FDR Adj. P Value"))))+
  geom_vline(xintercept = 0)+
  geom_point(size=1, aes(x = Diarrhea.Beta, y = -log10(Diarrhea.P.Val), group = factor(ifelse(p_df$Diarrhea.Adj.P.Val < 0.05,p_df$Letters,""))),position = position_dodge(width = 1)) +
  geom_label_repel(aes(x = Diarrhea.Beta, y = -log10(Diarrhea.P.Val), group = factor(ifelse(p_df$Diarrhea.Adj.P.Val < 0.05,p_df$Letters,""))), label.size = 0.1, label.padding = 0.1, box.padding = 0.5, min.segment.length = 0, point.size = NA, position = position_dodge(width = 1), size=2,label = factor(ifelse(p_df$Diarrhea.Adj.P.Val < 0.05,p_df$Letters,"")),color = "black", check_overlap = FALSE, max.overlaps = 127)+
 #ggtitle("Significant Genera") +
  xlab(bquote(beta~" Coefficient")) + 
  ylab(bquote("-log"[10]~"(P value)")) +
  #scale_x_break(c(-0.6, -18)) +
  scale_x_continuous(name = bquote(atop(beta["BMF"]~" Coefficient",italic("Diarrhea"))), 
                     guide = guide_axis(n.dodge = 2)) +
  theme(text = 
          element_text(size = 14), 
        plot.title = element_text(vjust = 0.5), 
        #plot.subtitle = element_text(size=8, hjust = 0.5), 
        legend.title = element_blank(), 
        axis.title.y = element_text(size = 8),
        axis.title.x = element_text(size = 8),
              legend.text  = element_text(size = 3),
              legend.position = "top",
              legend.key.size = unit(0.1, "lines"))+
          guides(shape = guide_legend(override.aes = list(size = 1.5)),
               color = guide_legend(override.aes = list(size = 1.5), nrow = 25),
               fill=guide_legend(title=NULL),
               aspect.ratio = 0.95)
Warning: Ignoring unknown parameters: check_overlap
plot0d
Warning: Use of `p_df$Diarrhea.Adj.P.Val` is discouraged. Use `Diarrhea.Adj.P.Val` instead.
Warning: Use of `p_df$Letters` is discouraged. Use `Letters` instead.
Warning: Use of `p_df$Diarrhea.Adj.P.Val` is discouraged. Use `Diarrhea.Adj.P.Val` instead.
Warning: Use of `p_df$Genera` is discouraged. Use `Genera` instead.
Warning: Use of `p_df$Diarrhea.Adj.P.Val` is discouraged. Use `Diarrhea.Adj.P.Val` instead.
Warning: Use of `p_df$Letters` is discouraged. Use `Letters` instead.
Warning: position_dodge requires non-overlapping x intervals
Warning: position_dodge requires non-overlapping x intervals
library(ggpubr)
figure1 <- ggarrange(plot0s,plot0m,plot0d, common.legend = FALSE, nrows = 1, widths=1,heights=3,ncols = 3, align = "hv", legend = "top") + theme(plot.margin = margin(0,0,0,0))
Warning: Use of `p_df$Const.Adj.P.Val` is discouraged. Use `Const.Adj.P.Val` instead.
Warning: Use of `p_df$Letters` is discouraged. Use `Letters` instead.
Warning: Use of `p_df$Const.Adj.P.Val` is discouraged. Use `Const.Adj.P.Val` instead.
Warning: Use of `p_df$Genera` is discouraged. Use `Genera` instead.
Warning: Use of `p_df$Const.Adj.P.Val` is discouraged. Use `Const.Adj.P.Val` instead.
Warning: Use of `p_df$Letters` is discouraged. Use `Letters` instead.
Warning: position_dodge requires non-overlapping x intervals
Warning: position_dodge requires non-overlapping x intervals
Warning: Removed 13 rows containing missing values (geom_label_repel).
Warning: Use of `p_df$Low.Adj.P.Val` is discouraged. Use `Low.Adj.P.Val` instead.
Warning: Use of `p_df$Letters` is discouraged. Use `Letters` instead.
Warning: Use of `p_df$Low.Adj.P.Val` is discouraged. Use `Low.Adj.P.Val` instead.
Warning: Use of `p_df$Genera` is discouraged. Use `Genera` instead.
Warning: Use of `p_df$Low.Adj.P.Val` is discouraged. Use `Low.Adj.P.Val` instead.
Warning: Use of `p_df$Letters` is discouraged. Use `Letters` instead.
Warning: position_dodge requires non-overlapping x intervals
Warning: position_dodge requires non-overlapping x intervals
Warning: Removed 27 rows containing missing values (geom_label_repel).
Warning: Use of `p_df$Diarrhea.Adj.P.Val` is discouraged. Use `Diarrhea.Adj.P.Val` instead.
Warning: Use of `p_df$Letters` is discouraged. Use `Letters` instead.
Warning: Use of `p_df$Diarrhea.Adj.P.Val` is discouraged. Use `Diarrhea.Adj.P.Val` instead.
Warning: Use of `p_df$Genera` is discouraged. Use `Genera` instead.
Warning: Use of `p_df$Diarrhea.Adj.P.Val` is discouraged. Use `Diarrhea.Adj.P.Val` instead.
Warning: Use of `p_df$Letters` is discouraged. Use `Letters` instead.
Warning: position_dodge requires non-overlapping x intervals
Warning: position_dodge requires non-overlapping x intervals
ggsave(
  "BMFvsGenera1.png",
  plot = figure1,
  device = NULL,
  path = NULL,
  scale = 1.75,
  width = NA,
  height = NA,
  units = c("in", "cm", "mm", "px"),
  dpi = 300,
  limitsize = TRUE,
  bg = NULL
)
Saving 12.8 x 7.88 in image

figure1
Error in grid.Call(C_convert, x, as.integer(whatfrom), as.integer(whatto),  : 
  Viewport has zero dimension(s)

sig = function(x){
  if(x < 0.001){"***"} 
  else if(x < 0.01){"**"}
  else if(x < 0.05){"*"}
  else{NA}}

df <- read.csv("gut_full.csv", check.names=F)
colnames(df) = gsub("nan", "Unclassified", colnames(df))
comparisons = list(c("Constipation","High Normal"),c("Low Normal","High Normal"),c("Diarrhea","High Normal"))
df$bowel <- factor(df$bowel, levels = c(1,2,3,4), labels = c("Constipation", "Low Normal", "High Normal", "Diarrhea"))
df_otus <- dplyr::select(df, -c("public_client_id","bowel","vendor_dashboard","sex","age","BMI_CALC","eGFR"))

df_otus <- as.data.frame(clr(as.matrix(df_otus)))
df_select <- dplyr::select(df, c(1:7))
df_otus <- cbind(df_select,df_otus)
df <- df_otus
dat <- df_otus

#Gut Genera
df$p.value <- NA
df$pval <- NULL
df$p.val <- NULL


counter <<- 1

test = function(x,y,z,j) {
  work <- NULL
  results <- NULL
  x = NULL
  y = NULL
  if (counter == 1) {z = comparisons[[1]][1]}
  else if (counter == 2) {z = comparisons[[2]][1]}
  else if (counter > 2) {z = comparisons[[3]][1]}
  temp <- data.frame("name" = NA, "p.value" = NA, "bowel" = NA)
  for (i in 1:20) {
    temp$name <- paste("genus_",span$Genera[[i]],sep="")
    temp$p.value <- span$Const.Adj.P.Val[[i]] 
    temp$bowel <- "Constipation"
    work <- rbind(work,temp)
    temp$p.value <- span$Low.Adj.P.Val[[i]] 
    temp$bowel <- "Low Normal"
    work <- rbind(work,temp)
    temp$p.value <- span$Diarrhea.Adj.P.Val[[i]] 
    temp$bowel <- "Diarrhea"
    work <- rbind(work,temp)
  }
  if (z[[1]][1] == comparisons[[1]][1]) {results <- list(p.value = work$p.value[3*(j-1)+1])}
  else if (z[[1]][1] == comparisons[[2]][1]) {results <- list(p.value = work$p.value[3*(j-1)+1+1]) }
  else if (z[[1]][1] == comparisons[[3]][1]) {results <- list(p.value = work$p.value[3*(j-1)+1+2])}
  counter<<-counter+1
  if (counter > 3) {counter<<-1}
  return(results)
}

myplots <- list()  # new empty list
df_test <- df
df_test[df_test==0] <- NA
for (genera in 1:20) {
  y_name <- paste("taxa_",span$Genera[genera],sep="")
  myplots[[genera]] <- local({
    plotlim_lower = min(
df_test[!is.na(df_test[y_name]),][y_name])
    plotlim_upper = max(
df_test[!is.na(df_test[y_name]),][y_name])
    plotlim_bar = plotlim_lower - 4
    plotlim_margin = 6
    genera <- genera
    plt <- ggplot(data = df_test, aes(x = bowel, y = .data[[y_name]], group = bowel)) +
    scale_x_discrete(guide = guide_axis(n.dodge = 2))+
    geom_jitter(aes(color = bowel),  size = 0.1, cex = 0.05) +
    geom_boxplot(data = df_test, alpha=0.0,outlier.shape = NA) +
    theme(text = element_text(size = 9)) +
    ggtitle(label = paste(span$Family[genera],"\n",span$Genus[genera],sep="")) +
    geom_signif(data = df_test, comparisons = comparisons, map_signif_level = sig, test = 'test', test.args = list(z = comparisons, j = genera), y_position = plotlim_bar,step_increase = 0.15,  size = 0.5, 
                textsize = 1.5,
                tip_length = c(0,0)) +
    coord_cartesian(ylim=c(plotlim_lower,plotlim_upper),clip="off")+
    labs(color = "BMF Category", y = ifelse((genera == 1 | genera  == 6 | genera  == 11 | genera == 16),"CLR Abundance","")) +
    guides(colour = guide_legend(override.aes = list(size=7), title.position = 'left', nrow = 1, ncol = 4)) +
    theme(plot.margin = unit(c(0,0,plotlim_margin,0), "cm"), 
          plot.title = element_text(size=5.75), 
          legend.title = element_text(size=10), 
          plot.subtitle = element_text(size=10), 
          legend.text = element_text(size=7),
          axis.text.x = element_blank(), 
          axis.text.y = element_text(size=7), 
          axis.title.y = element_text(size=7),
          axis.title.x = element_blank(),
          aspect.ratio = 0.95)
  })
}
Warning: Duplicated aesthetics after name standardisation: size
Warning: Duplicated aesthetics after name standardisation: size
Warning: Duplicated aesthetics after name standardisation: size
Warning: Duplicated aesthetics after name standardisation: size
Warning: Duplicated aesthetics after name standardisation: size
Warning: Duplicated aesthetics after name standardisation: size
Warning: Duplicated aesthetics after name standardisation: size
Warning: Duplicated aesthetics after name standardisation: size
Warning: Duplicated aesthetics after name standardisation: size
Warning: Duplicated aesthetics after name standardisation: size
Warning: Duplicated aesthetics after name standardisation: size
Warning: Duplicated aesthetics after name standardisation: size
Warning: Duplicated aesthetics after name standardisation: size
Warning: Duplicated aesthetics after name standardisation: size
Warning: Duplicated aesthetics after name standardisation: size
Warning: Duplicated aesthetics after name standardisation: size
Warning: Duplicated aesthetics after name standardisation: size
Warning: Duplicated aesthetics after name standardisation: size
Warning: Duplicated aesthetics after name standardisation: size
Warning: Duplicated aesthetics after name standardisation: size
library(gplots)
library(ggrepel)
library(ggbreak)

#Truncate the top 20 including verukkamansia 
title <- list()
for(i in seq(1:20)) { title[i] <- myplots[[c(i)]]$labels$title }
plots1 <- myplots[title %in% paste(
  span$Family,
  "\n",
  span$Genus,sep="")][1:20]
plots_final <- plots1[!sapply(plots1,is.null)]

final1 <- ggarrange(plotlist = plots_final[1:5], labels = LETTERS[1:5], legend = "top", align = "hv", font.label = list(size = 8), common.legend = TRUE, nrow = 1, ncol = 5) + theme(plot.margin = unit(c(0,0,0,0), "cm"))
Warning: Removed 3 rows containing non-finite values (stat_boxplot).
Warning: Removed 3 rows containing non-finite values (stat_signif).
Warning: Removed 3 rows containing missing values (geom_point).
Warning: Removed 5 rows containing missing values (geom_signif).
Warning: Removed 3 rows containing non-finite values (stat_boxplot).
Warning: Removed 3 rows containing non-finite values (stat_signif).
Warning: Removed 3 rows containing missing values (geom_point).
Warning: Removed 5 rows containing missing values (geom_signif).
Warning: Removed 56 rows containing non-finite values (stat_boxplot).
Warning: Removed 56 rows containing non-finite values (stat_signif).
Warning: Removed 56 rows containing missing values (geom_point).
Warning: Removed 8 rows containing missing values (geom_signif).
Warning: Removed 2 rows containing non-finite values (stat_boxplot).
Warning: Removed 2 rows containing non-finite values (stat_signif).
Warning: Removed 2 rows containing missing values (geom_point).
Warning: Removed 5 rows containing missing values (geom_signif).
Warning: Removed 85 rows containing non-finite values (stat_boxplot).
Warning: Removed 85 rows containing non-finite values (stat_signif).
Warning: Removed 85 rows containing missing values (geom_point).
Warning: Removed 8 rows containing missing values (geom_signif).
Warning: Removed 171 rows containing non-finite values (stat_boxplot).
Warning: Removed 171 rows containing non-finite values (stat_signif).
Warning: Removed 171 rows containing missing values (geom_point).
Warning: Removed 8 rows containing missing values (geom_signif).
final1

final2 <- ggarrange(plotlist = plots_final[6:10], labels = LETTERS[6:10], legend = "top", align = "hv", font.label = list(size = 8), common.legend = TRUE, nrow = 1, ncol = 5) + theme(plot.margin = unit(c(0,0,0,0), "cm"))
Warning: Removed 113 rows containing non-finite values (stat_boxplot).
Warning: Removed 113 rows containing non-finite values (stat_signif).
Warning: Removed 113 rows containing missing values (geom_point).
Warning: Removed 8 rows containing missing values (geom_signif).
Warning: Removed 113 rows containing non-finite values (stat_boxplot).
Warning: Removed 113 rows containing non-finite values (stat_signif).
Warning: Removed 113 rows containing missing values (geom_point).
Warning: Removed 8 rows containing missing values (geom_signif).
Warning: Removed 98 rows containing non-finite values (stat_boxplot).
Warning: Removed 98 rows containing non-finite values (stat_signif).
Warning: Removed 98 rows containing missing values (geom_point).
Warning: Removed 8 rows containing missing values (geom_signif).
Warning: Removed 607 rows containing non-finite values (stat_boxplot).
Warning: Removed 607 rows containing non-finite values (stat_signif).
Warning: Removed 607 rows containing missing values (geom_point).
Warning: Removed 8 rows containing missing values (geom_signif).
Warning: Removed 171 rows containing non-finite values (stat_boxplot).
Warning: Removed 171 rows containing non-finite values (stat_signif).
Warning: Removed 171 rows containing missing values (geom_point).
Warning: Removed 8 rows containing missing values (geom_signif).
Warning: Removed 4 rows containing non-finite values (stat_boxplot).
Warning: Removed 4 rows containing non-finite values (stat_signif).
Warning: Removed 4 rows containing missing values (geom_point).
Warning: Removed 7 rows containing missing values (geom_signif).
final2


final3 <- ggarrange(plotlist = plots_final[11:15], labels = LETTERS[11:15], legend = "top", align = "hv", font.label = list(size = 8), common.legend = TRUE, nrow = 1, ncol = 5) + theme(plot.margin = unit(c(0,0,0,0), "cm"))
Warning: Removed 762 rows containing non-finite values (stat_boxplot).
Warning: Removed 762 rows containing non-finite values (stat_signif).
Warning: Removed 762 rows containing missing values (geom_point).
Warning: Removed 8 rows containing missing values (geom_signif).
Warning: Removed 762 rows containing non-finite values (stat_boxplot).
Warning: Removed 762 rows containing non-finite values (stat_signif).
Warning: Removed 762 rows containing missing values (geom_point).
Warning: Removed 8 rows containing missing values (geom_signif).
Warning: Removed 271 rows containing non-finite values (stat_boxplot).
Warning: Removed 271 rows containing non-finite values (stat_signif).
Warning: Removed 271 rows containing missing values (geom_point).
Warning: Removed 5 rows containing missing values (geom_signif).
Warning: Removed 591 rows containing non-finite values (stat_boxplot).
Warning: Removed 591 rows containing non-finite values (stat_signif).
Warning: Removed 591 rows containing missing values (geom_point).
Warning: Removed 5 rows containing missing values (geom_signif).
Warning: Removed 147 rows containing non-finite values (stat_boxplot).
Warning: Removed 147 rows containing non-finite values (stat_signif).
Warning: Removed 147 rows containing missing values (geom_point).
Warning: Removed 5 rows containing missing values (geom_signif).
Warning: Removed 240 rows containing non-finite values (stat_boxplot).
Warning: Removed 240 rows containing non-finite values (stat_signif).
Warning: Removed 240 rows containing missing values (geom_point).
Warning: Removed 5 rows containing missing values (geom_signif).
final3

final4 <- ggarrange(plotlist = plots_final[16:20], labels = LETTERS[16:20], legend = "top", align = "hv", font.label = list(size = 8), common.legend = TRUE, nrow = 1, ncol = 5) + theme(plot.margin = unit(c(0,0,0,0), "cm"))
Warning: Removed 592 rows containing non-finite values (stat_boxplot).
Warning: Removed 592 rows containing non-finite values (stat_signif).
Warning: Removed 592 rows containing missing values (geom_point).
Warning: Removed 5 rows containing missing values (geom_signif).
Warning: Removed 592 rows containing non-finite values (stat_boxplot).
Warning: Removed 592 rows containing non-finite values (stat_signif).
Warning: Removed 592 rows containing missing values (geom_point).
Warning: Removed 5 rows containing missing values (geom_signif).
Warning: Removed 40 rows containing non-finite values (stat_boxplot).
Warning: Removed 40 rows containing non-finite values (stat_signif).
Warning: Removed 40 rows containing missing values (geom_point).
Warning: Removed 5 rows containing missing values (geom_signif).
Warning: Removed 331 rows containing non-finite values (stat_boxplot).
Warning: Removed 331 rows containing non-finite values (stat_signif).
Warning: Removed 331 rows containing missing values (geom_point).
Warning: Removed 5 rows containing missing values (geom_signif).
Warning: Removed 680 rows containing non-finite values (stat_boxplot).
Warning: Removed 680 rows containing non-finite values (stat_signif).
Warning: Removed 680 rows containing missing values (geom_point).
Warning: Removed 5 rows containing missing values (geom_signif).
Warning: Removed 20 rows containing non-finite values (stat_boxplot).
Warning: Removed 20 rows containing non-finite values (stat_signif).
Warning: Removed 20 rows containing missing values (geom_point).
Warning: Removed 5 rows containing missing values (geom_signif).
final4

counter<<-1
figure_main <- ggarrange(plotlist = plots_final[1:20], labels = LETTERS[1:20], legend = "top", align = "hv", common.legend = TRUE, nrow = 4, ncol = 5)
Warning: Removed 3 rows containing non-finite values (stat_boxplot).
Warning: Removed 3 rows containing non-finite values (stat_signif).
Warning: Removed 3 rows containing missing values (geom_point).
Warning: Removed 5 rows containing missing values (geom_signif).
Warning: Removed 3 rows containing non-finite values (stat_boxplot).
Warning: Removed 3 rows containing non-finite values (stat_signif).
Warning: Removed 3 rows containing missing values (geom_point).
Warning: Removed 5 rows containing missing values (geom_signif).
Warning: Removed 56 rows containing non-finite values (stat_boxplot).
Warning: Removed 56 rows containing non-finite values (stat_signif).
Warning: Removed 56 rows containing missing values (geom_point).
Warning: Removed 8 rows containing missing values (geom_signif).
Warning: Removed 2 rows containing non-finite values (stat_boxplot).
Warning: Removed 2 rows containing non-finite values (stat_signif).
Warning: Removed 2 rows containing missing values (geom_point).
Warning: Removed 5 rows containing missing values (geom_signif).
Warning: Removed 85 rows containing non-finite values (stat_boxplot).
Warning: Removed 85 rows containing non-finite values (stat_signif).
Warning: Removed 85 rows containing missing values (geom_point).
Warning: Removed 8 rows containing missing values (geom_signif).
Warning: Removed 171 rows containing non-finite values (stat_boxplot).
Warning: Removed 171 rows containing non-finite values (stat_signif).
Warning: Removed 171 rows containing missing values (geom_point).
Warning: Removed 8 rows containing missing values (geom_signif).
Warning: Removed 113 rows containing non-finite values (stat_boxplot).
Warning: Removed 113 rows containing non-finite values (stat_signif).
Warning: Removed 113 rows containing missing values (geom_point).
Warning: Removed 8 rows containing missing values (geom_signif).
Warning: Removed 98 rows containing non-finite values (stat_boxplot).
Warning: Removed 98 rows containing non-finite values (stat_signif).
Warning: Removed 98 rows containing missing values (geom_point).
Warning: Removed 8 rows containing missing values (geom_signif).
Warning: Removed 607 rows containing non-finite values (stat_boxplot).
Warning: Removed 607 rows containing non-finite values (stat_signif).
Warning: Removed 607 rows containing missing values (geom_point).
Warning: Removed 8 rows containing missing values (geom_signif).
Warning: Removed 171 rows containing non-finite values (stat_boxplot).
Warning: Removed 171 rows containing non-finite values (stat_signif).
Warning: Removed 171 rows containing missing values (geom_point).
Warning: Removed 8 rows containing missing values (geom_signif).
Warning: Removed 4 rows containing non-finite values (stat_boxplot).
Warning: Removed 4 rows containing non-finite values (stat_signif).
Warning: Removed 4 rows containing missing values (geom_point).
Warning: Removed 7 rows containing missing values (geom_signif).
Warning: Removed 762 rows containing non-finite values (stat_boxplot).
Warning: Removed 762 rows containing non-finite values (stat_signif).
Warning: Removed 762 rows containing missing values (geom_point).
Warning: Removed 8 rows containing missing values (geom_signif).
Warning: Removed 271 rows containing non-finite values (stat_boxplot).
Warning: Removed 271 rows containing non-finite values (stat_signif).
Warning: Removed 271 rows containing missing values (geom_point).
Warning: Removed 5 rows containing missing values (geom_signif).
Warning: Removed 591 rows containing non-finite values (stat_boxplot).
Warning: Removed 591 rows containing non-finite values (stat_signif).
Warning: Removed 591 rows containing missing values (geom_point).
Warning: Removed 5 rows containing missing values (geom_signif).
Warning: Removed 147 rows containing non-finite values (stat_boxplot).
Warning: Removed 147 rows containing non-finite values (stat_signif).
Warning: Removed 147 rows containing missing values (geom_point).
Warning: Removed 5 rows containing missing values (geom_signif).
Warning: Removed 240 rows containing non-finite values (stat_boxplot).
Warning: Removed 240 rows containing non-finite values (stat_signif).
Warning: Removed 240 rows containing missing values (geom_point).
Warning: Removed 5 rows containing missing values (geom_signif).
Warning: Removed 592 rows containing non-finite values (stat_boxplot).
Warning: Removed 592 rows containing non-finite values (stat_signif).
Warning: Removed 592 rows containing missing values (geom_point).
Warning: Removed 5 rows containing missing values (geom_signif).
Warning: Removed 40 rows containing non-finite values (stat_boxplot).
Warning: Removed 40 rows containing non-finite values (stat_signif).
Warning: Removed 40 rows containing missing values (geom_point).
Warning: Removed 5 rows containing missing values (geom_signif).
Warning: Removed 331 rows containing non-finite values (stat_boxplot).
Warning: Removed 331 rows containing non-finite values (stat_signif).
Warning: Removed 331 rows containing missing values (geom_point).
Warning: Removed 5 rows containing missing values (geom_signif).
Warning: Removed 680 rows containing non-finite values (stat_boxplot).
Warning: Removed 680 rows containing non-finite values (stat_signif).
Warning: Removed 680 rows containing missing values (geom_point).
Warning: Removed 5 rows containing missing values (geom_signif).
Warning: Removed 20 rows containing non-finite values (stat_boxplot).
Warning: Removed 20 rows containing non-finite values (stat_signif).
Warning: Removed 20 rows containing missing values (geom_point).
Warning: Removed 5 rows containing missing values (geom_signif).
ggsave(
  "BMFvsGenera2.png",
  plot = final1,
  device = NULL,
  path = NULL,
  scale = 1.5,
  width = NA,
  height = NA,
  units = c("in", "cm", "mm", "px"),
  dpi = 300,
  limitsize = TRUE,
  bg = NULL
)
Saving 10.9 x 6.76 in image
ggsave(
  "BMFvsGenera3.png",
  plot = final2,
  device = NULL,
  path = NULL,
  scale = 1.5,
  width = NA,
  height = NA,
  units = c("in", "cm", "mm", "px"),
  dpi = 300,
  limitsize = TRUE,
  bg = NULL
)
Saving 10.9 x 6.76 in image
ggsave(
  "BMFvsGenera4.png",
  plot = final3,
  device = NULL,
  path = NULL,
  scale = 1.5,
  width = NA,
  height = NA,
  units = c("in", "cm", "mm", "px"),
  dpi = 300,
  limitsize = TRUE,
  bg = NULL
)
Saving 10.9 x 6.76 in image
ggsave(
  "BMFvsGenera5.png",
  plot = final4,
  device = NULL,
  path = NULL,
  scale = 1.5,
  width = NA,
  height = NA,
  units = c("in", "cm", "mm", "px"),
  dpi = 300,
  limitsize = TRUE,
  bg = NULL
)
Saving 10.9 x 6.76 in image
ggsave(
  "BMFvsGeneraMain.png",
  plot = final_main,
  device = NULL,
  path = NULL,
  scale = 1.5,
  width = NA,
  height = NA,
  units = c("in", "cm", "mm", "px"),
  dpi = 300,
  limitsize = TRUE,
  bg = NULL
)
Saving 10.9 x 6.76 in image

ggsave(
  "BMFvsGeneraMain.png",
  plot = final_main,
  device = NULL,
  path = NULL,
  scale = 0.5,
  width = NA,
  height = NA,
  units = c("in", "cm", "mm", "px"),
  dpi = 300,
  limitsize = TRUE,
  bg = NULL
)
Saving 7 x 7 in image
LS0tCnRpdGxlOiAiQnVpbGQgYSBwaHlsb3NlcSBvYmplY3QiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCkxldCdzIHN0YXJ0IGJ5IHJlYWRpbmcgeW91ciBkYXRhOgoKYGBge3J9CiMgSW1wb3J0IGxpYnJhcmllczoKIyBMb2FkIGxpYnJhcmllcwojIE5vdGU6IGNvbW1lbnRlZC1vdXQgbGlicmFyaWVzIGFyZSBleHBlcmltZW50YWwgbGlicmFyaWVzIGZvciBvdGhlciBmdW5jdGlvbnMgbm90IHVzZWQgaW4gdGhpcyBmaW5hbCBhbmFseXNpcyBmaWxlCmxpYnJhcnkobGltbWEpCiNsaWJyYXJ5KERFU2VxMikKbGlicmFyeShlZGdlUikKI2xpYnJhcnkoUnN1YnJlYWQpCmxpYnJhcnkoc25zKQojbGlicmFyeShHbGltbWEpCmxpYnJhcnkoZGF0YS50YWJsZSkKbGlicmFyeSh0aWR5cikKI2xpYnJhcnkobWFncml0dHIpCmxpYnJhcnkodGlkeXZlcnNlKQojbGlicmFyeShzalBsb3QpCiNsaWJyYXJ5KHNqbGFiZWxsZWQpCmxpYnJhcnkoc2ptaXNjKQpsaWJyYXJ5KGdncGxvdDIpCiNsaWJyYXJ5KGVmZmVjdHMpCiNsaWJyYXJ5KGJyb29tKQojbGlicmFyeShHR2FsbHkpCiNsaWJyYXJ5KGVtbWVhbnMpCiNsaWJyYXJ5KGdncHVicikKI3RoZW1lX3NldCh0aGVtZV9wdWJyKCkpCmxpYnJhcnkoY29ybmNvYikKbGlicmFyeShwaHlsb3NlcSkKCiMgSW1wb3J0IGRhdGE6Cm90dXMgPC0gcmVhZC5jc3YoImd1dF9mdWxsLmNzdiIsIGNoZWNrLm5hbWVzPUYpCnRheGEgPC0gcmVhZC5jc3YoInRheGEuY3N2IixzZXA9J1x0JykKb3R1cyRzZXggPC0gZmFjdG9yKG90dXMkc2V4KSAjZmFjdG9yaXplIHNleApvdHVzJHZlbmRvcl9kYXNoYm9hcmQgPC0gZmFjdG9yKG90dXMkdmVuZG9yX2Rhc2hib2FyZCkKb3R1cyRib3dlbCA8LSBmYWN0b3IoYXMubnVtZXJpYyhmYWN0b3Iob3R1cyRib3dlbCwgbGV2ZWxzID0gYygxLDIsMyw0KSwgbGFiZWxzID0gYygxLDIsMyw0KSkpKQpvdHVzIDwtIG90dXNbIHdoaWNoKG90dXMkdmVuZG9yX2Rhc2hib2FyZCA9PSAiU2Vjb25kIEdlbm9tZSIgfCBvdHVzJHZlbmRvcl9kYXNoYm9hcmQgPT0gInJlc2VhcmNoLW1pY3JvYmlvbWUiKSxdICMga2VlcCBvbmx5IGRhdGEgd2hlcmUgdmVuZG9yIGlzIGV4cGxpY2l0Cm90dXMkdmVuZG9yX2Rhc2hib2FyZCA9IHN0cl9yZXBsYWNlX2FsbChvdHVzJHZlbmRvcl9kYXNoYm9hcmQsInJlc2VhcmNoLW1pY3JvYmlvbWUiLCJETkEgR2Vub3RlayIpCm90dXMkdmVuZG9yX2Rhc2hib2FyZCA8LSBmYWN0b3Iob3R1cyR2ZW5kb3JfZGFzaGJvYXJkKSAjIGZhY3Rvcml6ZSB2ZW5kb3IKI290dXNbIHdoaWNoKG90dXMkdmVuZG9yX2Rhc2hib2FyZCA9PSAiU2Vjb25kIEdlbm9tZSIpLF0Kb3R1cyA8LSB3aXRoaW4ob3R1cywgYm93ZWwgPC0gcmVsZXZlbChib3dlbCwgcmVmID0gMykpCgojIFByZS1wcm9jZXNzaW5nIGFuZCBjaGVja2luZyB2YWxpZGl0eSBvZiBkYXRhCiMgQWxnb3JpdGhtcyBwcm92aWRlZCBieSBDaHJpc3RpYW4gRGllbmVyLCBQaEQ6CmRhdCA8LSBvdHVzCm90dXMgPC0gb3R1c1shZHVwbGljYXRlZChvdHVzJHB1YmxpY19jbGllbnRfaWQpLCBdCmdlbnVzX2NvbHMgPC0gZ3JlcGwoInRheGFfIiwgbmFtZXMob3R1cykpCnJvd25hbWVzKG90dXMpIDwtIG90dXMkcHVibGljX2NsaWVudF9pZApzZGF0YSA8LSBvdHVzWywgIWdlbnVzX2NvbHNdCmJvd2VsIDwtIHBhc3RlMChzZGF0YVsnYm93ZWwnXSkKdGFibGUoc2RhdGFbJ2Jvd2VsJ10pCm90dXMgPC0gYXMubWF0cml4KG90dXNbLCBnZW51c19jb2xzXSkKY29sbmFtZXMob3R1cykgPC0gZ3N1YigidGF4YV8iLCAiIiwgY29sbmFtZXMob3R1cykpCnRheF9tYXRyaXggPC0gYXMubWF0cml4KHRheGFbLCAyOm5jb2wodGF4YSldKQpyb3duYW1lcyh0YXhfbWF0cml4KSA8LSB0YXhhWywgMV0KYXMuZGF0YS5mcmFtZShvdHVzKQpgYGAKCgpOb3cgd2UgY29udmVydCBpdCB0byBmaXQgaW4gYSBwaHlsb3NlcSBvYmplY3QuIFdlIG5lZWQgdG8gZnVsZmlsbCB0aGUgZm9sbG93aW5nIHJ1bGVzOgoKMS4gVGhlIE9UVSB0YWJsZSBpcyBhIG1hdHJpeCB3aXRoIHJvd3MgYmVpbmcgc2FtcGxlcyBhbmQgZWFjaCBjb2x1bW4gYmVpbmcgYSB0YXhvbi4KMi4gVGhlIHRheG9ub215IHRhYmxlIG11c3QgYmUgYSBtYXRyaXggd2l0aCByb3dzIGJlaW5nIHRheGEgYW5kIGNvbHVtbnMgYmVpbmcgcmFua3MuCjMuIFRoZSBzYW1wbGUgZGF0YSBtdXN0IGJlIGRhdGEgZnJhbWUgd2l0aCByb3dzIGJlaW5nIHNhbXBsZXMuCgpUbyBkb3VibGUgY2hlY2sgaWYgZXZlcnl0aGluZyB3b3JrcyBsZXQncyBkbyBzb21lIHZhbGlkaXR5IGNoZWNrczoKCmBgYHtyfQpzdG9waWZub3QoYWxsKHJvd25hbWVzKG90dXMpICVpbiUgcm93bmFtZXMoc2RhdGEpKSkKc3RvcGlmbm90KG5yb3cob3R1cykgPT0gbnJvdyhzZGF0YSkpCnByaW50KCJzYW1wbGUgbmFtZXMgbWF0Y2giKQoKc3RvcGlmbm90KGFsbChjb2xuYW1lcyhvdHVzKSAlaW4lIHJvd25hbWVzKHRheF9tYXRyaXgpKSkKc3RvcGlmbm90KG5jb2wob3R1cykgPT0gbnJvdyh0YXhfbWF0cml4KSkKc3RvcGlmbm90KCFhbnlEdXBsaWNhdGVkKHRheF9tYXRyaXgpKQpwcmludCgidGF4YSBsb29rIG9rYXkiKQoKc3RvcGlmbm90KCFhbnlEdXBsaWNhdGVkKHNkYXRhKSkKcHJpbnQoInNhbXBsZSBkYXRhIGxvb2tzIG9rYXkiKQpgYGAKCklmIHRoYXQgcGFzc2VzIHdlIGNhbiBnbyBhaGVhZCBhbmQgYnVpbGQgb3VyIHBoeWxvc2VxIG9iamVjdC4KCmBgYHtyfQpwcyA8LSBwaHlsb3NlcSgKICBvdHVfdGFibGUob3R1cywgdGF4YV9hcmVfcm93cyA9IEZBTFNFKSwKICB0YXhfdGFibGUodGF4X21hdHJpeCksCiAgc2FtcGxlX2RhdGEoc2RhdGEpCikKCnBzCmBgYAoKYGBge3J9Cm5hbWVzKHNhbXBsZV9kYXRhKHBzKSkKYm93ZWwgPC0gc2FtcGxlX2RhdGEocHMpJGJvd2VsCgoKYGBgCgpgYGB7cn0KI0RpZmZlcmVudGlhbCBUZXN0CmR2X2FuYWx5c2lzIDwtIGRpZmZlcmVudGlhbFRlc3QoZm9ybXVsYSA9IH4gYm93ZWwgKyBzZXggKyBhZ2UgKyBCTUlfQ0FMQyArIHZlbmRvcl9kYXNoYm9hcmQgKyBlR0ZSLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwaGkuZm9ybXVsYSA9IH4gMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9ybXVsYV9udWxsID0gfiBzZXggKyBhZ2UgKyBCTUlfQ0FMQyArIHZlbmRvcl9kYXNoYm9hcmQgKyBlR0ZSLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwaGkuZm9ybXVsYV9udWxsID0gfiAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gcHMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRlc3QgPSAiTFJUIiwgYm9vdCA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmdWxsX291dHB1dCA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZkcl9jdXRvZmYgPSAwLjA1KQpgYGAKCgpgYGB7cn0KI1NlZSB0aGUgc2lnbmlmaWNhbnQgdGF4YSBmcm9tIHRoZSBjb21wdXRhdGlvbjoKZHZfYW5hbHlzaXMkc2lnbmlmaWNhbnRfdGF4YQpgYGAKCgpgYGB7cn0Kc2F2ZVJEUyhkdl9hbmFseXNpcywgImNvcm5jb2JfYWxsMy5yZHMiKQojTG9hZCB0aGUgLnJkcyBmaWxlIGFzICJkdl9hbmFseXNpcyIgdG8gY29udGludWUgZnJvbSBhbHJlYWR5IGNvbXB1dGVkIGR2X2FuYWx5c2lzIGZpbGUgZnJvbSBiZWZvcmUuCiNUaGlzIHdheSB5b3UgZG9uJ3QgbmVlZCB0byBydW4gdGhlIGNvbXB1dGF0aW9uIGFsbCBvdmVyIGFnYWluIGVhY2ggdGltZSB5b3Ugd2FudCB0byBydW4gdGhlIGNvZGUgZnJvbSBoZXJlIGJlbG93OgpgYGAKCgpgYGB7cn0KbGlicmFyeShEYXRhQ29tYmluZSkKdGF4YTwtZHZfYW5hbHlzaXMkYWxsX21vZGVscwpkdl9hbmFseXNpcyRzaWduaWZpY2FudF90YXhhCmFzLmRhdGEuZnJhbWUoZHZfYW5hbHlzaXMkcF9mZHIpCnRheGFfcCA8LSBEcm9wTkEoYXMuZGF0YS5mcmFtZShkdl9hbmFseXNpcyRwX2ZkciksIFZhciA9ICJkdl9hbmFseXNpcyRwX2ZkciIpCnRheGFfcFsxXQp0YXhhW1sxXV0kY29lZmZpY2llbnRzCmBgYAoKCmBgYHtyfQpzYW1wbGVfZGF0YShhcml2YWxlX3BoeWxvX2RmKSAKCiNUb20ncyBjb2RlOgojUmFyZWZ5IGdlbm90ZWsgZGF0YXNldCB0byBldmVuIGRlcHRoCiNyYXJlZnkgZXZlbiBkZXB0aCBpcyBhIGNvbW1hbmQgaW4gcGh5bG9zZXEKI3JhcmVmeSBmb3IgYWxwaGEgZGl2ZXJzaXR5LCBidXQgbm90IGZvciBjb3JuY29iCnJhcmVmaWVkX2dlbm90ZWs9cmFyZWZ5X2V2ZW5fZGVwdGgoYXJpdmFsZV9waHlsb19kZiwgc2FtcGxlLnNpemUgPSBtaW4oc2FtcGxlX3N1bXMoYXJpdmFsZV9waHlsb19kZikpLAogIHJuZ3NlZWQgPSAxMTEsIHJlcGxhY2UgPSBGQUxTRSwgdHJpbU9UVXMgPSBUUlVFLCB2ZXJib3NlID0gVFJVRSkKCnJpY2huZXNzIDwtIGVzdGltYXRlX3JpY2huZXNzKHJhcmVmaWVkX2dlbm90ZWssIG1lYXN1cmVzPWMoIlNoYW5ub24iLCJPYnNlcnZlZCIpKQojUmVmZXIgdG8gQ2hyaXN0aWFuIChwaHl0cmVlPykgb24gUEQgd2hvbGUgdHJlZSAocGh5bG9zZXEgYWRkaXRpb25hbCBQRCB3aG9sZSB0cmVlIHBhY2thZ2UsIGNoZWNrIGl0KSBhbmQgYWRkIGl0IHRvIHJpY2huZXNzIGNvbHVtbiBvbiBkZi4KYGBgCgoKYGBge3J9CnJpY2huZXNzJHB1YmxpY19jbGllbnRfaWQgPC1zYW1wbGVfZGF0YShyYXJlZmllZF9nZW5vdGVrKSRwdWJsaWNfY2xpZW50X2lkCiNSZWZlciB0byBDaHJpc3RpYW4gKHBoeXRyZWU/KSBvbiBQRCB3aG9sZSB0cmVlIChwaHlsb3NlcSBhZGRpdGlvbmFsIFBEIHdob2xlIHRyZWUgcGFja2FnZSwgY2hlY2sgaXQpIGFuZCBhZGQgaXQgdG8gcmljaG5lc3MgY29sdW1uIG9uIGRmLgoKbGlicmFyeShidG9vbHMpCnJpY2huZXNzJFBpZWxvdSA8LSByaWNobmVzcyRTaGFubm9uL3JpY2huZXNzJE9ic2VydmVkCgpyaWNobmVzcwpgYGAKCgpgYGB7cn0KaGlzdChyaWNobmVzcyRQaWVsb3UsCiAgICAgbWFpbiA9ICJQaWVsb3UncyBFdmVubmVzcyAoU2hhbm5vbi9PYnNlcnZlZCBBU1YpIiwKICAgICB4bGFiID0gIkV2ZW5uZXNzIiwKICAgICB4bGltID0gYygwLDAuMDUpLAogICAgIGJyZWFrcyA9IDIwMCkKCmhpc3QocmljaG5lc3MkU2hhbm5vbiwKICAgICBtYWluID0gIlNoYW5ub24gRGl2ZXJzaXR5IiwKICAgICB4bGFiID0gIkRpdmVyc2l0eSBJbmRleCIsCiAgICAgeGxpbSA9IGMoMCw2KSwKICAgICBicmVha3MgPSAyMCkKCmhpc3QocmljaG5lc3MkT2JzZXJ2ZWQsCiAgICAgbWFpbiA9ICJPYnNlcnZlZCBBU1ZzIiwKICAgICB4bGFiID0gIkFTVnMiLAogICAgIHhsaW0gPSBjKDAsMTAwMCksCiAgICAgYnJlYWtzID0gMzApCmBgYAoKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGdncG1pc2MpCmxpYnJhcnkocXVhbnRyZWcpCmxpYnJhcnkoYnJvb20pCmxpYnJhcnkoZ2diZWVzd2FybSkKbGlicmFyeShnZ3NpZ25pZikKbGlicmFyeShnZ2lubmFyZHMpCmxpYnJhcnkoZ2dwdWJyKQpsaWJyYXJ5KGdncG1pc2MpCmxpYnJhcnkoYnJvb20ubWl4ZWQpCmxpYnJhcnkoc2NhbGVzKQojbGlicmFyeShubG1lKQoKc2FtLm4gPC0gZnVuY3Rpb24oeCl7CiAgcmV0dXJuKGMoeSA9IG1lYW4oeCksIGxhYmVsID0gbGVuZ3RoKHgpKSkKfQoKY29tYmluYXRpb25zIDwtIGxpc3QoYygiQ29uc3RpcGF0aW9uIiwiTG93IE5vcm1hbCIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjKCJDb25zdGlwYXRpb24iLCJIaWdoIE5vcm1hbCIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjKCJDb25zdGlwYXRpb24iLCJEaWFycmhlYSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjKCJMb3cgTm9ybWFsIiwiSGlnaCBOb3JtYWwiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYygiTG93IE5vcm1hbCIsIkRpYXJyaGVhIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGMoIkhpZ2ggTm9ybWFsIiwiRGlhcnJoZWEiKSkKZGF0JGJvd2VsIDwtIGZhY3RvcihkYXQkYm93ZWwsIGxldmVscyA9IGMoIkNvbnN0aXBhdGlvbiIsICJMb3cgTm9ybWFsIiwgIkhpZ2ggTm9ybWFsIiwgIkRpYXJyaGVhIiksIGxhYmVscyA9IGMoIkNvbnN0aXBhdGlvbiIsICJMb3cgTm9ybWFsIiwgIkhpZ2ggTm9ybWFsIiwgIkRpYXJyaGVhIikpCmBgYAoKCmBgYHtyfQpsaWJyYXJ5KGNvbXBvc2l0aW9ucykKZGYgPC0gcmVhZC5jc3YoImd1dF9mdWxsLmNzdiIsIGNoZWNrLm5hbWVzPUYpCmNvbG5hbWVzKGRmKSA9IGdzdWIoIm5hbiIsICJVbmNsYXNzaWZpZWQiLCBjb2xuYW1lcyhkZikpCmNvbXBhcmlzb25zID0gbGlzdChjKCJDb25zdGlwYXRpb24iLCJIaWdoIE5vcm1hbCIpLGMoIkxvdyBOb3JtYWwiLCJIaWdoIE5vcm1hbCIpLGMoIkRpYXJyaGVhIiwiSGlnaCBOb3JtYWwiKSkKZGYkYm93ZWwgPC0gZmFjdG9yKGRmJGJvd2VsLCBsZXZlbHMgPSBjKDEsMiwzLDQpLCBsYWJlbHMgPSBjKCJDb25zdGlwYXRpb24iLCAiTG93IE5vcm1hbCIsICJIaWdoIE5vcm1hbCIsICJEaWFycmhlYSIpKQpkZl9vdHVzIDwtIGRwbHlyOjpzZWxlY3QoZGYsIC1jKCJwdWJsaWNfY2xpZW50X2lkIiwiYm93ZWwiLCJ2ZW5kb3JfZGFzaGJvYXJkIiwic2V4IiwiYWdlIiwiQk1JX0NBTEMiLCJlR0ZSIikpCgpkZl9vdHVzIDwtIGFzLmRhdGEuZnJhbWUoY2xyKGFzLm1hdHJpeChkZl9vdHVzKSkpCmRmX3NlbGVjdCA8LSBkcGx5cjo6c2VsZWN0KGRmLCBjKDE6NykpCmRmX290dXMgPC0gY2JpbmQoZGZfc2VsZWN0LGRmX290dXMpCmRmIDwtIGRmX290dXMKZGF0IDwtIGRmX290dXMKCmxpYnJhcnkoZ2dyZXBlbCkKc2FtLm4gPC0gZnVuY3Rpb24oeCl7cmV0dXJuKGMoeSA9IG1lYW4oeCksIGxhYmVsID0gbGVuZ3RoKHgpKSl9CgojIGdncGxvdDIgcGxvdHMKbGlicmFyeShncGxvdHMpCmxpYnJhcnkoZ2dyZXBlbCkKbGlicmFyeShnZ2JyZWFrKQpsaWJyYXJ5KHNvbW1lcikKCiNCTUYgZGYKY29uc3QgPC0gYygpCmNvbnN0X3AgPC0gYygpCmxvdyA8LSBjKCkKbG93X3AgPC0gYygpCmRpYXJyaGVhIDwtIGMoKQpkaWFycmhlYV9wIDwtIGMoKQp0YXhhX25hbWVzIDwtIGMoKQpmYW1pbHlfbmFtZXMgPC0gYygpCmdlbnVzX25hbWVzIDwtIGMoKQpsaWtlbGlob29kIDwtIGMoKQphZGpfcCA8LSBjKCkKbmFtZXMoZHZfYW5hbHlzaXMkcCkgPSBnc3ViKCJuYW4iLCAiVW5jbGFzc2lmaWVkIiwgbmFtZXMoZHZfYW5hbHlzaXMkcCkpCgojZHZfYW5hbHlzaXMkYWxsX21vZGVsc1tvcmRlcihkdl9hbmFseXNpcyRwW29yZGVyKG5hbWVzKGR2X2FuYWx5c2lzJHApKV0pXSkKZm9yIChpIGluIDE6bGVuZ3RoKGR2X2FuYWx5c2lzJGFsbF9tb2RlbHNbbmFtZXMoZHZfYW5hbHlzaXMkcCldKSkgewogIGNvbnN0X3BbaV0gPC0gZHZfYW5hbHlzaXMkYWxsX21vZGVsc1tbaV1dJGNvZWZmaWNpZW50c1syLDRdCiAgY29uc3RbaV0gPC0gZHZfYW5hbHlzaXMkYWxsX21vZGVsc1tbaV1dJGNvZWZmaWNpZW50c1syLDFdCiAgbG93X3BbaV0gPC0gZHZfYW5hbHlzaXMkYWxsX21vZGVsc1tbaV1dJGNvZWZmaWNpZW50c1szLDRdCiAgbG93W2ldIDwtIGR2X2FuYWx5c2lzJGFsbF9tb2RlbHNbW2ldXSRjb2VmZmljaWVudHNbMywxXQogIGRpYXJyaGVhX3BbaV0gPC0gZHZfYW5hbHlzaXMkYWxsX21vZGVsc1tbaV1dJGNvZWZmaWNpZW50c1s0LDRdCiAgZGlhcnJoZWFbaV0gPC0gZHZfYW5hbHlzaXMkYWxsX21vZGVsc1tbaV1dJGNvZWZmaWNpZW50c1s0LDFdCiAgdGF4YV9uYW1lc1tpXSA8LSBuYW1lcyhkdl9hbmFseXNpcyRwKVtpXQogIGZhbWlseV9uYW1lc1tpXSA8LSBzdHJzcGxpdCh0YXhhX25hbWVzW2ldLCcuJyxmaXhlZD1UUlVFKVtbMV1dWzVdCiAgZ2VudXNfbmFtZXNbaV0gPC0gc3Ryc3BsaXQodGF4YV9uYW1lc1tpXSwnLicsZml4ZWQ9VFJVRSlbWzFdXVs2XQogIGxpa2VsaWhvb2RbaV0gPC0gZHZfYW5hbHlzaXMkYWxsX21vZGVsc1tbaV1dJGxvZ0wKICBhZGpfcFtpXSA8LSBkdl9hbmFseXNpcyRwX2ZkcltbaV1dCn0KCmdlbnVzX25hbWVzW2ldIDwtIHN0cnNwbGl0KHRheGFfbmFtZXNbaV0sJy4nLGZpeGVkPVRSVUUpW1sxXV1bNl0KCnBfZGYgPC0gYmluZF9jb2xzKHRheGFfbmFtZXMsZmFtaWx5X25hbWVzLGdlbnVzX25hbWVzLCBsaWtlbGlob29kLCBhZGpfcCwgY29uc3QsY29uc3RfcCxsb3csbG93X3AsZGlhcnJoZWEsZGlhcnJoZWFfcCkKbmFtZXMocF9kZikgPC0gYygiR2VuZXJhIiwiRmFtaWx5IiwiR2VudXMiLCJMb2dMIiwiQWRqLlAiLCJDb25zdC5CZXRhIiwiQ29uc3QuUC5WYWwiLCJMb3cuQmV0YSIsIkxvdy5QLlZhbCIsIkRpYXJyaGVhLkJldGEiLCJEaWFycmhlYS5QLlZhbCIpCnBfZGYkQ29tYmluZWQgPC0gcGFzdGUocF9kZiRGYW1pbHkscF9kZiRHZW51cykKYWIgPC0gY29sU3VtcyhkZl9vdHVzW25hbWVzKGRmX290dXMpICVpbiUgcGFzdGUoInRheGFfIixuYW1lcyhkdl9hbmFseXNpcyRwKSxzZXA9IiIpXSkvY29sU3VtcyghIWRmX290dXNbbmFtZXMoZGZfb3R1cykgJWluJSBwYXN0ZSgidGF4YV8iLG5hbWVzKGR2X2FuYWx5c2lzJHApLHNlcD0iIildKQpwX2RmJE1lYW4uQWJ1bmRhbmNlIDwtIGFiW3Bhc3RlKCJ0YXhhXyIscF9kZiRHZW5lcmEsc2VwPSIiKV0KCnBfZGYkQ29uc3QuQWRqLlAuVmFsIDwtIHAuYWRqdXN0KGNvbnN0X3AsIG1ldGhvZCA9ICJmZHIiLCBuID0gbGVuZ3RoKGNvbnN0X3ApKQpwX2RmJExvdy5BZGouUC5WYWwgPC0gcC5hZGp1c3QobG93X3AsIG1ldGhvZCA9ICJmZHIiLCBuID0gbGVuZ3RoKGxvd19wKSkKcF9kZiREaWFycmhlYS5BZGouUC5WYWwgPC0gcC5hZGp1c3QoZGlhcnJoZWFfcCwgbWV0aG9kID0gImZkciIsIG4gPSBsZW5ndGgoZGlhcnJoZWFfcCkpCgpwX2RmIDwtIHBfZGZbb3JkZXIoLXBfZGYkTWVhbi5BYnVuZGFuY2UpLF0KCgpzZXQgPC0gc3Vic2V0KHBfZGZbd2hpY2gocF9kZiRBZGouUCA8IDAuMDUpLF0sIEdlbnVzICE9ICdVbmNsYXNzaWZpZWQnKQpzZXQgPC0gc3Vic2V0KHNldFtvcmRlcigtc2V0JE1lYW4uQWJ1bmRhbmNlKSxdLCBHZW51cyAhPSAnVW5jbGFzc2lmaWVkJykKCgphYnVuZGFudF9saXN0IDwtIGxpc3QoKQphYnVuZGFudF9nZW51cyA8LSBsaXN0KCkKYWJ1bmRhbnQgPC0gcGFzdGUoInRheGFfIixzZXRbb3JkZXIoLXNldCRNZWFuLkFidW5kYW5jZSksXSRHZW5lcmEsc2VwPSIiKQpmb3IgKGkgaW4gMTo2OCkgewogIGFidW5kYW50X2xpc3RbaV0gPC0gcGFzdGUoc3Ryc3BsaXQoYWJ1bmRhbnRbaV0sJy4nLGZpeGVkPVRSVUUpW1sxXV1bNV0sc3Ryc3BsaXQoYWJ1bmRhbnRbaV0sJy4nLGZpeGVkPVRSVUUpW1sxXV1bNl0pCiAgYWJ1bmRhbnRfZ2VudXNbaV0gPC0gcGFzdGUoc3Ryc3BsaXQoYWJ1bmRhbnRbaV0sJy4nLGZpeGVkPVRSVUUpW1sxXV1bNl0pCn0KCiN0b3AgMTAgbW9zdCBhYnVuZGFudCBub24tdW5jbGFzc2lmaWVkIGhpdHMKYWJ1bmRhbnRfdHJ1bmMgPC0gc2V0W21hdGNoKGFidW5kYW50X2xpc3RbIWlzLm5hKHNldCRDb21iaW5lZFttYXRjaChhYnVuZGFudF9saXN0LHNldCRDb21iaW5lZCldKV0sc2V0JENvbWJpbmVkKSxdW3doaWNoKHNldCRBZGouUDwwLjA1KSxdJENvbWJpbmVkWzE6MTBdCmAlIWluJWAgPC0gTmVnYXRlKGAlaW4lYCkKdCA8LSBzZXRbc2V0JENvbWJpbmVkICUhaW4lIGFidW5kYW50X3RydW5jLF0KI3RbIWlzLm5hKHRbb3JkZXIodCRBZGouUCksXSRNZWFuLkFidW5kYW5jZSksXVtvcmRlcih0JEFkai5QKSxdCgpzcGFuIDwtIHJiaW5kKHNldFtvcmRlcihzZXRbLW9yZGVyKHNldFshc2V0JENvbWJpbmVkICVpbiUgYWJ1bmRhbnRfdHJ1bmMsXSRBZGouUCksXVt3aGljaChzZXQkQWRqLlA8MC4wNSksXSRNZWFuLkFidW5kYW5jZSAlIWluJSBhYnVuZGFudF90cnVuYyksXVsxOjEwLF0sCnRbbWF0Y2goJ0Fra2VybWFuc2lhY2VhZSBBa2tlcm1hbnNpYScsdCRDb21iaW5lZCksXSwKdFtvcmRlcih0JENvbnN0LkFkai5QLlZhbCksXVsxOjksXSkKc3BhbiRMZXR0ZXJzIDwtIExFVFRFUlNbMToyMF0KCnBfZGYkTGV0dGVycyA8LSBjKE5BKQp0ZXN0IDwtIHJiaW5kKHNwYW4scF9kZltwX2RmJENvbWJpbmVkICUhaW4lIHNwYW4kQ29tYmluZWQsXSkKdGVzdCA8LSB0ZXN0WyFkdXBsaWNhdGVkKHRlc3QkR2VuZXJhKSxdCiN0ZXN0W29yZGVyKHRlc3RbIWR1cGxpY2F0ZWQodGVzdCksXSRMZXR0ZXJzKSxdCnBfZGYgPC0gdGVzdApwX2RmIDwtIHBfZGZbb3JkZXIocF9kZiRBZGouUCksXQpwX2RmIDwtIHBfZGZbb3JkZXIoLXBfZGYkTWVhbi5BYnVuZGFuY2UpLF0KCgptb2RlbCA9IHkgfiB4CmRmX251bSA8LSBtZXJnZShyaWNobmVzcywgZGZfb3R1cywgYnk9InB1YmxpY19jbGllbnRfaWQiKQpkZl9udW0gPC0gd2l0aGluKGRmX251bSwgYm93ZWwgPC0gcmVsZXZlbChib3dlbCwgcmVmID0gJ0hpZ2ggTm9ybWFsJykpCmQxX3Bsb3QgPC0gbG0oUGllbG91IH4gYm93ZWwsIGRhdGEgPSBkZl9udW0pCnB2YWwxID0gc3VtbWFyeShkMV9wbG90KSRjb2VmZmljaWVudHNbMiw0XQpyMSA9IHN1bW1hcnkoZDFfcGxvdCkkYWRqLnIuc3F1YXJlZApwdmFsMQpyMQoKZDEgPC0gZ2dwbG90KGRhdGEgPSBkZl9udW0sIGFlcyh4ID0gZmFjdG9yKGJvd2VsLCBsZXZlbCA9IGMoIkNvbnN0aXBhdGlvbiIsICJMb3cgTm9ybWFsIiwgIkhpZ2ggTm9ybWFsIiwgIkRpYXJyaGVhIiksIGxhYmVscyA9IGMoIkNvbnN0aXBhdGlvbiIsICJMb3cgTm9ybWFsIiwgIkhpZ2ggTm9ybWFsIiwgIkRpYXJyaGVhIikpLCB5ID0gUGllbG91LCBncm91cCA9IGZhY3Rvcihib3dlbCkpKSArCiAgc2NhbGVfeF9kaXNjcmV0ZShicXVvdGUoYXRvcCh+aXRhbGljKCJhZGogUiIpXjJ+IiA9ICJ+Lihmb3JtYXRDKGFzLm51bWVyaWMocjEpLDMpKSx+aXRhbGljKCJQIHZhbHVlIil+IiA9ICJ+Lihmb3JtYXRDKGFzLm51bWVyaWMocHZhbDEpLDMpKSkpKSsKICBnZW9tX2JlZXN3YXJtKGFlcyhjb2xvciA9IGJvd2VsKSwgY2V4ID0gMC41KSArCiAgZ2VvbV9ib3hwbG90KGFscGhhPTApICsKICB5bGltKDAuMDA1LDAuMDUpKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIGZvcm11bGEgPSB5IH4geCwgYWVzKGdyb3VwID0gMSkpICsKICBnZ3RpdGxlKGxhYmVsID0gIkMpXG5QaWVsb3UncyBFdmVubmVzcyB2cyBCTUYiKSArCiAgeGxhYigiQm93ZWwgTW92ZW1lbnQgRnJlcXVlbmN5IChCTUYpIikgKwogIHlsYWIoIlBpZWxvdSdzIEV2ZW5uZXNzIikgKwogIHNjYWxlX2NvbG91cl9kaXNjcmV0ZShuYW1lPSJCTUYgQ2F0ZWdvcnkiLCBsaW1pdHMgPSBjKCJDb25zdGlwYXRpb24iLCAiTG93IE5vcm1hbCIsICJIaWdoIE5vcm1hbCIsICJEaWFycmhlYSIpLCBsYWJlbHM9YygiQ29uc3RpcGF0aW9uIiwgIkxvdyBOb3JtYWwiLCAiSGlnaCBOb3JtYWwiLCAiRGlhcnJoZWEiKSkgKwogIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplPTcpKSkgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xMCksIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLCBheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCkpCmQxCgptb2RlbCA9IHkgfiB4CmQyX3Bsb3QgPC0gbG0oU2hhbm5vbiB+IGJvd2VsLCBkYXRhID0gZGZfbnVtKQpwdmFsMiA9IHN1bW1hcnkoZDJfcGxvdCkkY29lZmZpY2llbnRzWzIsNF0KcjIgPSBzdW1tYXJ5KGQyX3Bsb3QpJGFkai5yLnNxdWFyZWQKcHZhbDIKcjIKCmQyIDwtIGdncGxvdChkYXRhID0gZGZfbnVtLCBhZXMoeCA9IGZhY3Rvcihib3dlbCwgbGV2ZWwgPSBjKCJDb25zdGlwYXRpb24iLCAiTG93IE5vcm1hbCIsICJIaWdoIE5vcm1hbCIsICJEaWFycmhlYSIpLCBsYWJlbHMgPSBjKCJDb25zdGlwYXRpb24iLCAiTG93IE5vcm1hbCIsICJIaWdoIE5vcm1hbCIsICJEaWFycmhlYSIpKSwgeSA9IFNoYW5ub24sIGdyb3VwID0gYm93ZWwpKSArCiAgc2NhbGVfeF9kaXNjcmV0ZShicXVvdGUoYXRvcCh+aXRhbGljKCJhZGogUiIpXjJ+IiA9ICJ+Lihmb3JtYXRDKGFzLm51bWVyaWMocjIpLDMpKSx+aXRhbGljKCJQIHZhbHVlIil+IiA9ICJ+Lihmb3JtYXRDKGFzLm51bWVyaWMocHZhbDIpLDMpKSkpKSsKICBnZW9tX2JlZXN3YXJtKGFlcyhjb2xvciA9IGZhY3Rvcihib3dlbCkpLCBjZXggPSAwLjUpICsKICBnZW9tX2JveHBsb3QoYWxwaGE9MCkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIGZvcm11bGEgPSB5IH4geCwgYWVzKGdyb3VwID0gMSkpICsKICBnZ3RpdGxlKGxhYmVsID0gIkIpXG5TaGFubm9uIERpdmVyc2l0eSB2cyBCTUYiKSArCiAgeGxhYigiQm93ZWwgTW92ZW1lbnQgRnJlcXVlbmN5IChCTUYpIikgKwogIHlsYWIoIlNoYW5ub24gRGl2ZXJzaXR5IikgKwogIHNjYWxlX2NvbG91cl9kaXNjcmV0ZShuYW1lPSJCTUYgQ2F0ZWdvcnkiLCBsaW1pdHMgPSBjKCJDb25zdGlwYXRpb24iLCAiTG93IE5vcm1hbCIsICJIaWdoIE5vcm1hbCIsICJEaWFycmhlYSIpLCBsYWJlbHM9YygiQ29uc3RpcGF0aW9uIiwgIkxvdyBOb3JtYWwiLCAiSGlnaCBOb3JtYWwiLCAiRGlhcnJoZWEiKSkgKwogIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplPTcpKSkgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xMCksIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLCBheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCkpCmQyCgptb2RlbCA9IHkgfiB4CmQzX3Bsb3QgPC0gbG0oT2JzZXJ2ZWQgfiBib3dlbCwgZGF0YSA9IGRmX251bSkKcHZhbDMgPSBzdW1tYXJ5KGQzX3Bsb3QpJGNvZWZmaWNpZW50c1syLDRdCnIzID0gc3VtbWFyeShkM19wbG90KSRhZGouci5zcXVhcmVkCnB2YWwzCnIzCgpkMyA8LSBnZ3Bsb3QoZGF0YSA9IGRmX251bSwgYWVzKHggPSBmYWN0b3IoYm93ZWwsIGxldmVsID0gYygiQ29uc3RpcGF0aW9uIiwgIkxvdyBOb3JtYWwiLCAiSGlnaCBOb3JtYWwiLCAiRGlhcnJoZWEiKSwgbGFiZWxzID0gYygiQ29uc3RpcGF0aW9uIiwgIkxvdyBOb3JtYWwiLCAiSGlnaCBOb3JtYWwiLCAiRGlhcnJoZWEiKSksIHkgPSBPYnNlcnZlZCwgZ3JvdXAgPSBib3dlbCkpKwogIHNjYWxlX3hfZGlzY3JldGUoYnF1b3RlKGF0b3Aofml0YWxpYygiYWRqIFIiKV4yfiIgPSAifi4oZm9ybWF0Qyhhcy5udW1lcmljKHIzKSwzKSksfml0YWxpYygiUCB2YWx1ZSIpfiIgPSAifi4oZm9ybWF0Qyhhcy5udW1lcmljKHB2YWwzKSwzKSkpKSkrCiAgZ2VvbV9iZWVzd2FybShhZXMoY29sb3IgPSBmYWN0b3IoYm93ZWwpKSwgY2V4ID0gMC41KSArCiAgZ2VvbV9ib3hwbG90KGFscGhhPTApICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBmb3JtdWxhID0geSB+IHgsIGFlcyhncm91cCA9IDEpKSArCiAgZ2d0aXRsZShsYWJlbCA9ICJBKVxuT2JzZXJ2ZWQgQVNWcyB2cyBCTUYiKSArCiAgeGxhYigiQm93ZWwgTW92ZW1lbnQgRnJlcXVlbmN5IChCTUYpIikgKwogIHlsYWIoIk9ic2VydmVkIEFTVnMiKSArCiAgc2NhbGVfY29sb3VyX2Rpc2NyZXRlKG5hbWU9IkJNRiBDYXRlZ29yeSIsIGxpbWl0cyA9IGMoIkNvbnN0aXBhdGlvbiIsICJMb3cgTm9ybWFsIiwgIkhpZ2ggTm9ybWFsIiwgIkRpYXJyaGVhIiksIGxhYmVscz1jKCJDb25zdGlwYXRpb24iLCAiTG93IE5vcm1hbCIsICJIaWdoIE5vcm1hbCIsICJEaWFycmhlYSIpKSArCiAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemU9NykpKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTEwKSwgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSkKZDMKClBTTyA8LSBnZ2FycmFuZ2UoZDMsIGQyLCBkMSwgbGVnZW5kID0gInRvcCIsIGFsaWduID0gImh2IiwgY29tbW9uLmxlZ2VuZCA9IFRSVUUsIHdpZHRocyA9IGMoNyw3LDcpLCBoZWlnaHRzID0gYygyMCwyMCwyMCksIG5yb3cgPSAxLCBuY29sID0gMykrIHRoZW1lKHBsb3QubWFyZ2luID0gbWFyZ2luKDAsMCwwLDApKQpQU08KZ2dzYXZlKAogICJQU092Qk1GLnBuZyIsCiAgcGxvdCA9IFBTTywKICBkZXZpY2UgPSBOVUxMLAogIHBhdGggPSBOVUxMLAogIHNjYWxlID0gMSwKICB3aWR0aCA9IE5BLAogIGhlaWdodCA9IE5BLAogIHVuaXRzID0gYygiaW4iLCAiY20iLCAibW0iLCAicHgiKSwKICBkcGkgPSAzMDAsCiAgbGltaXRzaXplID0gVFJVRSwKICBiZyA9IE5VTEwKKQpgYGAKCgpgYGB7cn0KCiMgU2lnbmlmaWNhbnQgR2VuZXJhIFBsb3QgKHBsb3QgMCkKcGxvdDBzIDwtIGdncGxvdChwX2RmLCBtYXBwaW5nID0gYWVzKHg9Q29uc3QuQmV0YSx5ID0gLWxvZzEwKENvbnN0LlAuVmFsKSwgY29sb3IgPSBpZmVsc2UocF9kZiRDb25zdC5BZGouUC5WYWwgPCAwLjA1LHBfZGYkR2VuZXJhLCItIEZEUiBBZGouIFAgVmFsdWUiKSxncm91cCA9IGZhY3RvcihpZmVsc2UocF9kZiRDb25zdC5BZGouUC5WYWwgPCAwLjA1LHBfZGYkR2VuZXJhLCItIEZEUiBBZGouIFAgVmFsdWUiKSkpKSsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwKSsKICBnZW9tX3BvaW50KHNpemU9MSwgYWVzKHggPSBDb25zdC5CZXRhLCB5ID0gLWxvZzEwKENvbnN0LlAuVmFsKSwgZ3JvdXAgPSBmYWN0b3IoaWZlbHNlKHBfZGYkQ29uc3QuQWRqLlAuVmFsIDwgMC4wNSxwX2RmJExldHRlcnMsIiIpKSkscG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpKSArCiAgZ2VvbV9sYWJlbF9yZXBlbChhZXMoeCA9IENvbnN0LkJldGEsIHkgPSAtbG9nMTAoQ29uc3QuUC5WYWwpLCBncm91cCA9IGZhY3RvcihpZmVsc2UocF9kZiRDb25zdC5BZGouUC5WYWwgPCAwLjA1LHBfZGYkTGV0dGVycywiIikpKSwgbGFiZWwuc2l6ZSA9IDAuMSwgbGFiZWwucGFkZGluZyA9IDAuMSwgYm94LnBhZGRpbmcgPSAwLjUsIG1pbi5zZWdtZW50Lmxlbmd0aCA9IDAsIHBvaW50LnNpemUgPSBOQSwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpLCBzaXplPTIsbGFiZWwgPSBmYWN0b3IoaWZlbHNlKHBfZGYkQ29uc3QuQWRqLlAuVmFsIDwgMC4wNSxwX2RmJExldHRlcnMsIiIpKSxjb2xvciA9ICJibGFjayIsIGNoZWNrX292ZXJsYXAgPSBGQUxTRSwgbWF4Lm92ZXJsYXBzID0gMTI3KSsKICNnZ3RpdGxlKCJTaWduaWZpY2FudCBHZW5lcmEiKSArCiAgeGxhYihicXVvdGUoYmV0YX4iIENvZWZmaWNpZW50IikpICsgCiAgeWxhYihicXVvdGUoIi1sb2ciWzEwXX4iKFAgdmFsdWUpIikpICsgCiAgI3NjYWxlX3hfYnJlYWsoYygtMC42LCAtMTgpKSArCiAgc2NhbGVfeF9jb250aW51b3VzKG5hbWUgPSBicXVvdGUoYXRvcChiZXRhWyJCTUYiXX4iIENvZWZmaWNpZW50IixpdGFsaWMoIkNvbnN0aXBhdGlvbiIpKSksIAogICAgICAgICAgICAgICAgICAgICBndWlkZSA9IGd1aWRlX2F4aXMobi5kb2RnZSA9IDIpLCBsaW1pdHMgPSBjKC0xLjUsMS41KSkgKwogIHRoZW1lKHRleHQgPSAKICAgICAgICAgIGVsZW1lbnRfdGV4dChzaXplID0gMTQpLCAKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHZqdXN0ID0gMC41KSwgCiAgICAgICAgI3Bsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT04LCBoanVzdCA9IDAuNSksIAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSwKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpLAogICAgICAgICAgICAgIGxlZ2VuZC50ZXh0ICA9IGVsZW1lbnRfdGV4dChzaXplID0gMyksCiAgICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIsCiAgICAgICAgICAgICAgbGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjEsICJsaW5lcyIpKSsKICAgICAgICAgIGd1aWRlcyhzaGFwZSA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSAxLjUpKSwKICAgICAgICAgICAgICAgY29sb3IgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMS41KSwgbnJvdyA9IDI1KSwKICAgICAgICAgICAgICAgZmlsbD1ndWlkZV9sZWdlbmQodGl0bGU9TlVMTCksCiAgICAgICAgICAgICAgIGFzcGVjdC5yYXRpbyA9IDAuOTUpCnBsb3QwcwoKIyBTaWduaWZpY2FudCBHZW5lcmEgUGxvdCAocGxvdCAwKQpwbG90MG0gPC0gZ2dwbG90KHBfZGYsIG1hcHBpbmcgPSBhZXMoeD1Mb3cuQmV0YSx5ID0gLWxvZzEwKExvdy5QLlZhbCksIGNvbG9yID0gaWZlbHNlKHBfZGYkTG93LkFkai5QLlZhbCA8IDAuMDUscF9kZiRHZW5lcmEsIi0gRkRSIEFkai4gUCBWYWx1ZSIpLGdyb3VwID0gZmFjdG9yKGlmZWxzZShwX2RmJExvdy5BZGouUC5WYWwgPCAwLjA1LHBfZGYkR2VuZXJhLCItIEZEUiBBZGouIFAgVmFsdWUiKSkpKSsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwKSsKICBnZW9tX3BvaW50KHNpemU9MSwgYWVzKHggPSBMb3cuQmV0YSwgeSA9IC1sb2cxMChMb3cuUC5WYWwpLCBncm91cCA9IGZhY3RvcihpZmVsc2UocF9kZiRMb3cuQWRqLlAuVmFsIDwgMC4wNSxwX2RmJExldHRlcnMsIiIpKSkscG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpKSArCiAgZ2VvbV9sYWJlbF9yZXBlbChhZXMoeCA9IExvdy5CZXRhLCB5ID0gLWxvZzEwKExvdy5QLlZhbCksIGdyb3VwID0gZmFjdG9yKGlmZWxzZShwX2RmJExvdy5BZGouUC5WYWwgPCAwLjA1LHBfZGYkTGV0dGVycywiIikpKSwgbGFiZWwuc2l6ZSA9IDAuMSwgbGFiZWwucGFkZGluZyA9IDAuMSwgYm94LnBhZGRpbmcgPSAwLjUsIG1pbi5zZWdtZW50Lmxlbmd0aCA9IDAsIHBvaW50LnNpemUgPSBOQSwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpLCBzaXplPTIsbGFiZWwgPSBmYWN0b3IoaWZlbHNlKHBfZGYkTG93LkFkai5QLlZhbCA8IDAuMDUscF9kZiRMZXR0ZXJzLCIiKSksY29sb3IgPSAiYmxhY2siLCBjaGVja19vdmVybGFwID0gRkFMU0UsIG1heC5vdmVybGFwcyA9IDEyNykrCiAjZ2d0aXRsZSgiU2lnbmlmaWNhbnQgR2VuZXJhIikgKwogIHhsYWIoYnF1b3RlKGJldGF+IiBDb2VmZmljaWVudCIpKSArIAogIHlsYWIoYnF1b3RlKCItbG9nIlsxMF1+IihQIHZhbHVlKSIpKSArCiAgI3NjYWxlX3hfYnJlYWsoYygtMC42LCAtMTgpKSArCiAgc2NhbGVfeF9jb250aW51b3VzKG5hbWUgPSBicXVvdGUoYXRvcChiZXRhWyJCTUYiXX4iIENvZWZmaWNpZW50IixpdGFsaWMoIkxvdyBOb3JtYWwiKSkpLCAKICAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPSBndWlkZV9heGlzKG4uZG9kZ2UgPSAyKSkgKwogIHRoZW1lKHRleHQgPSAKICAgICAgICAgIGVsZW1lbnRfdGV4dChzaXplID0gMTQpLCAKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHZqdXN0ID0gMC41KSwgCiAgICAgICAgI3Bsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT04LCBoanVzdCA9IDAuNSksIAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSwKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpLAogICAgICAgICAgICAgIGxlZ2VuZC50ZXh0ICA9IGVsZW1lbnRfdGV4dChzaXplID0gMyksCiAgICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIsCiAgICAgICAgICAgICAgbGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjEsICJsaW5lcyIpKSsKICAgICAgICAgIGd1aWRlcyhzaGFwZSA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSAxLjUpKSwKICAgICAgICAgICAgICAgY29sb3IgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMS41KSwgbnJvdyA9IDI1KSwKICAgICAgICAgICAgICAgZmlsbD1ndWlkZV9sZWdlbmQodGl0bGU9TlVMTCksCiAgICAgICAgICAgICAgIGFzcGVjdC5yYXRpbyA9IDAuOTUpCnBsb3QwbQoKIyBTaWduaWZpY2FudCBHZW5lcmEgUGxvdCAocGxvdCAwKQpwbG90MGQgPC0gZ2dwbG90KHBfZGYsIG1hcHBpbmcgPSBhZXMoeD1EaWFycmhlYS5CZXRhLHkgPSAtbG9nMTAoRGlhcnJoZWEuUC5WYWwpLCBjb2xvciA9IGlmZWxzZShwX2RmJERpYXJyaGVhLkFkai5QLlZhbCA8IDAuMDUscF9kZiRHZW5lcmEsIi0gRkRSIEFkai4gUCBWYWx1ZSIpLGdyb3VwID0gZmFjdG9yKGlmZWxzZShwX2RmJERpYXJyaGVhLkFkai5QLlZhbCA8IDAuMDUscF9kZiRHZW5lcmEsIi0gRkRSIEFkai4gUCBWYWx1ZSIpKSkpKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDApKwogIGdlb21fcG9pbnQoc2l6ZT0xLCBhZXMoeCA9IERpYXJyaGVhLkJldGEsIHkgPSAtbG9nMTAoRGlhcnJoZWEuUC5WYWwpLCBncm91cCA9IGZhY3RvcihpZmVsc2UocF9kZiREaWFycmhlYS5BZGouUC5WYWwgPCAwLjA1LHBfZGYkTGV0dGVycywiIikpKSxwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMSkpICsKICBnZW9tX2xhYmVsX3JlcGVsKGFlcyh4ID0gRGlhcnJoZWEuQmV0YSwgeSA9IC1sb2cxMChEaWFycmhlYS5QLlZhbCksIGdyb3VwID0gZmFjdG9yKGlmZWxzZShwX2RmJERpYXJyaGVhLkFkai5QLlZhbCA8IDAuMDUscF9kZiRMZXR0ZXJzLCIiKSkpLCBsYWJlbC5zaXplID0gMC4xLCBsYWJlbC5wYWRkaW5nID0gMC4xLCBib3gucGFkZGluZyA9IDAuNSwgbWluLnNlZ21lbnQubGVuZ3RoID0gMCwgcG9pbnQuc2l6ZSA9IE5BLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMSksIHNpemU9MixsYWJlbCA9IGZhY3RvcihpZmVsc2UocF9kZiREaWFycmhlYS5BZGouUC5WYWwgPCAwLjA1LHBfZGYkTGV0dGVycywiIikpLGNvbG9yID0gImJsYWNrIiwgY2hlY2tfb3ZlcmxhcCA9IEZBTFNFLCBtYXgub3ZlcmxhcHMgPSAxMjcpKwogI2dndGl0bGUoIlNpZ25pZmljYW50IEdlbmVyYSIpICsKICB4bGFiKGJxdW90ZShiZXRhfiIgQ29lZmZpY2llbnQiKSkgKyAKICB5bGFiKGJxdW90ZSgiLWxvZyJbMTBdfiIoUCB2YWx1ZSkiKSkgKwogICNzY2FsZV94X2JyZWFrKGMoLTAuNiwgLTE4KSkgKwogIHNjYWxlX3hfY29udGludW91cyhuYW1lID0gYnF1b3RlKGF0b3AoYmV0YVsiQk1GIl1+IiBDb2VmZmljaWVudCIsaXRhbGljKCJEaWFycmhlYSIpKSksIAogICAgICAgICAgICAgICAgICAgICBndWlkZSA9IGd1aWRlX2F4aXMobi5kb2RnZSA9IDIpKSArCiAgdGhlbWUodGV4dCA9IAogICAgICAgICAgZWxlbWVudF90ZXh0KHNpemUgPSAxNCksIAogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQodmp1c3QgPSAwLjUpLCAKICAgICAgICAjcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTgsIGhqdXN0ID0gMC41KSwgCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpLAogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gOCksCiAgICAgICAgICAgICAgbGVnZW5kLnRleHQgID0gZWxlbWVudF90ZXh0KHNpemUgPSAzKSwKICAgICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAidG9wIiwKICAgICAgICAgICAgICBsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuMSwgImxpbmVzIikpKwogICAgICAgICAgZ3VpZGVzKHNoYXBlID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDEuNSkpLAogICAgICAgICAgICAgICBjb2xvciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSAxLjUpLCBucm93ID0gMjUpLAogICAgICAgICAgICAgICBmaWxsPWd1aWRlX2xlZ2VuZCh0aXRsZT1OVUxMKSwKICAgICAgICAgICAgICAgYXNwZWN0LnJhdGlvID0gMC45NSkKcGxvdDBkCgpsaWJyYXJ5KGdncHVicikKZmlndXJlMSA8LSBnZ2FycmFuZ2UocGxvdDBzLHBsb3QwbSxwbG90MGQsIGNvbW1vbi5sZWdlbmQgPSBGQUxTRSwgbnJvd3MgPSAxLCB3aWR0aHM9MSxoZWlnaHRzPTMsbmNvbHMgPSAzLCBhbGlnbiA9ICJodiIsIGxlZ2VuZCA9ICJ0b3AiKSArIHRoZW1lKHBsb3QubWFyZ2luID0gbWFyZ2luKDAsMCwwLDApKQoKZ2dzYXZlKAogICJCTUZ2c0dlbmVyYTEucG5nIiwKICBwbG90ID0gZmlndXJlMSwKICBkZXZpY2UgPSBOVUxMLAogIHBhdGggPSBOVUxMLAogIHNjYWxlID0gMS43NSwKICB3aWR0aCA9IE5BLAogIGhlaWdodCA9IE5BLAogIHVuaXRzID0gYygiaW4iLCAiY20iLCAibW0iLCAicHgiKSwKICBkcGkgPSAzMDAsCiAgbGltaXRzaXplID0gVFJVRSwKICBiZyA9IE5VTEwKKQoKZmlndXJlMQpgYGAKCmBgYHtyfQpzaWcgPSBmdW5jdGlvbih4KXsKICBpZih4IDwgMC4wMDEpeyIqKioifSAKICBlbHNlIGlmKHggPCAwLjAxKXsiKioifQogIGVsc2UgaWYoeCA8IDAuMDUpeyIqIn0KICBlbHNle05BfX0KCmRmIDwtIHJlYWQuY3N2KCJndXRfZnVsbC5jc3YiLCBjaGVjay5uYW1lcz1GKQpjb2xuYW1lcyhkZikgPSBnc3ViKCJuYW4iLCAiVW5jbGFzc2lmaWVkIiwgY29sbmFtZXMoZGYpKQpjb21wYXJpc29ucyA9IGxpc3QoYygiQ29uc3RpcGF0aW9uIiwiSGlnaCBOb3JtYWwiKSxjKCJMb3cgTm9ybWFsIiwiSGlnaCBOb3JtYWwiKSxjKCJEaWFycmhlYSIsIkhpZ2ggTm9ybWFsIikpCmRmJGJvd2VsIDwtIGZhY3RvcihkZiRib3dlbCwgbGV2ZWxzID0gYygxLDIsMyw0KSwgbGFiZWxzID0gYygiQ29uc3RpcGF0aW9uIiwgIkxvdyBOb3JtYWwiLCAiSGlnaCBOb3JtYWwiLCAiRGlhcnJoZWEiKSkKZGZfb3R1cyA8LSBkcGx5cjo6c2VsZWN0KGRmLCAtYygicHVibGljX2NsaWVudF9pZCIsImJvd2VsIiwidmVuZG9yX2Rhc2hib2FyZCIsInNleCIsImFnZSIsIkJNSV9DQUxDIiwiZUdGUiIpKQoKZGZfb3R1cyA8LSBhcy5kYXRhLmZyYW1lKGNscihhcy5tYXRyaXgoZGZfb3R1cykpKQpkZl9zZWxlY3QgPC0gZHBseXI6OnNlbGVjdChkZiwgYygxOjcpKQpkZl9vdHVzIDwtIGNiaW5kKGRmX3NlbGVjdCxkZl9vdHVzKQpkZiA8LSBkZl9vdHVzCmRhdCA8LSBkZl9vdHVzCgojR3V0IEdlbmVyYQpkZiRwLnZhbHVlIDwtIE5BCmRmJHB2YWwgPC0gTlVMTApkZiRwLnZhbCA8LSBOVUxMCgoKY291bnRlciA8PC0gMQoKdGVzdCA9IGZ1bmN0aW9uKHgseSx6LGopIHsKICB3b3JrIDwtIE5VTEwKICByZXN1bHRzIDwtIE5VTEwKICB4ID0gTlVMTAogIHkgPSBOVUxMCiAgaWYgKGNvdW50ZXIgPT0gMSkge3ogPSBjb21wYXJpc29uc1tbMV1dWzFdfQogIGVsc2UgaWYgKGNvdW50ZXIgPT0gMikge3ogPSBjb21wYXJpc29uc1tbMl1dWzFdfQogIGVsc2UgaWYgKGNvdW50ZXIgPiAyKSB7eiA9IGNvbXBhcmlzb25zW1szXV1bMV19CiAgdGVtcCA8LSBkYXRhLmZyYW1lKCJuYW1lIiA9IE5BLCAicC52YWx1ZSIgPSBOQSwgImJvd2VsIiA9IE5BKQogIGZvciAoaSBpbiAxOjIwKSB7CiAgICB0ZW1wJG5hbWUgPC0gcGFzdGUoImdlbnVzXyIsc3BhbiRHZW5lcmFbW2ldXSxzZXA9IiIpCiAgICB0ZW1wJHAudmFsdWUgPC0gc3BhbiRDb25zdC5BZGouUC5WYWxbW2ldXSAKICAgIHRlbXAkYm93ZWwgPC0gIkNvbnN0aXBhdGlvbiIKICAgIHdvcmsgPC0gcmJpbmQod29yayx0ZW1wKQogICAgdGVtcCRwLnZhbHVlIDwtIHNwYW4kTG93LkFkai5QLlZhbFtbaV1dIAogICAgdGVtcCRib3dlbCA8LSAiTG93IE5vcm1hbCIKICAgIHdvcmsgPC0gcmJpbmQod29yayx0ZW1wKQogICAgdGVtcCRwLnZhbHVlIDwtIHNwYW4kRGlhcnJoZWEuQWRqLlAuVmFsW1tpXV0gCiAgICB0ZW1wJGJvd2VsIDwtICJEaWFycmhlYSIKICAgIHdvcmsgPC0gcmJpbmQod29yayx0ZW1wKQogIH0KICBpZiAoeltbMV1dWzFdID09IGNvbXBhcmlzb25zW1sxXV1bMV0pIHtyZXN1bHRzIDwtIGxpc3QocC52YWx1ZSA9IHdvcmskcC52YWx1ZVszKihqLTEpKzFdKX0KICBlbHNlIGlmICh6W1sxXV1bMV0gPT0gY29tcGFyaXNvbnNbWzJdXVsxXSkge3Jlc3VsdHMgPC0gbGlzdChwLnZhbHVlID0gd29yayRwLnZhbHVlWzMqKGotMSkrMSsxXSkgfQogIGVsc2UgaWYgKHpbWzFdXVsxXSA9PSBjb21wYXJpc29uc1tbM11dWzFdKSB7cmVzdWx0cyA8LSBsaXN0KHAudmFsdWUgPSB3b3JrJHAudmFsdWVbMyooai0xKSsxKzJdKX0KICBjb3VudGVyPDwtY291bnRlcisxCiAgaWYgKGNvdW50ZXIgPiAzKSB7Y291bnRlcjw8LTF9CiAgcmV0dXJuKHJlc3VsdHMpCn0KCm15cGxvdHMgPC0gbGlzdCgpICAjIG5ldyBlbXB0eSBsaXN0CmRmX3Rlc3QgPC0gZGYKZGZfdGVzdFtkZl90ZXN0PT0wXSA8LSBOQQpmb3IgKGdlbmVyYSBpbiAxOjIwKSB7CiAgeV9uYW1lIDwtIHBhc3RlKCJ0YXhhXyIsc3BhbiRHZW5lcmFbZ2VuZXJhXSxzZXA9IiIpCiAgbXlwbG90c1tbZ2VuZXJhXV0gPC0gbG9jYWwoewogICAgcGxvdGxpbV9sb3dlciA9IG1pbigKZGZfdGVzdFshaXMubmEoZGZfdGVzdFt5X25hbWVdKSxdW3lfbmFtZV0pCiAgICBwbG90bGltX3VwcGVyID0gbWF4KApkZl90ZXN0WyFpcy5uYShkZl90ZXN0W3lfbmFtZV0pLF1beV9uYW1lXSkKICAgIHBsb3RsaW1fYmFyID0gcGxvdGxpbV9sb3dlciAtIDQKICAgIHBsb3RsaW1fbWFyZ2luID0gNgogICAgZ2VuZXJhIDwtIGdlbmVyYQogICAgcGx0IDwtIGdncGxvdChkYXRhID0gZGZfdGVzdCwgYWVzKHggPSBib3dlbCwgeSA9IC5kYXRhW1t5X25hbWVdXSwgZ3JvdXAgPSBib3dlbCkpICsKICAgIHNjYWxlX3hfZGlzY3JldGUoZ3VpZGUgPSBndWlkZV9heGlzKG4uZG9kZ2UgPSAyKSkrCiAgICBnZW9tX2ppdHRlcihhZXMoY29sb3IgPSBib3dlbCksICBzaXplID0gMC4xLCBjZXggPSAwLjA1KSArCiAgICBnZW9tX2JveHBsb3QoZGF0YSA9IGRmX3Rlc3QsIGFscGhhPTAuMCxvdXRsaWVyLnNoYXBlID0gTkEpICsKICAgIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDkpKSArCiAgICBnZ3RpdGxlKGxhYmVsID0gcGFzdGUoc3BhbiRGYW1pbHlbZ2VuZXJhXSwiXG4iLHNwYW4kR2VudXNbZ2VuZXJhXSxzZXA9IiIpKSArCiAgICBnZW9tX3NpZ25pZihkYXRhID0gZGZfdGVzdCwgY29tcGFyaXNvbnMgPSBjb21wYXJpc29ucywgbWFwX3NpZ25pZl9sZXZlbCA9IHNpZywgdGVzdCA9ICd0ZXN0JywgdGVzdC5hcmdzID0gbGlzdCh6ID0gY29tcGFyaXNvbnMsIGogPSBnZW5lcmEpLCB5X3Bvc2l0aW9uID0gcGxvdGxpbV9iYXIsc3RlcF9pbmNyZWFzZSA9IDAuMTUsICBzaXplID0gMC41LCAKICAgICAgICAgICAgICAgIHRleHRzaXplID0gMS41LAogICAgICAgICAgICAgICAgdGlwX2xlbmd0aCA9IGMoMCwwKSkgKwogICAgY29vcmRfY2FydGVzaWFuKHlsaW09YyhwbG90bGltX2xvd2VyLHBsb3RsaW1fdXBwZXIpLGNsaXA9Im9mZiIpKwogICAgbGFicyhjb2xvciA9ICJCTUYgQ2F0ZWdvcnkiLCB5ID0gaWZlbHNlKChnZW5lcmEgPT0gMSB8IGdlbmVyYSAgPT0gNiB8IGdlbmVyYSAgPT0gMTEgfCBnZW5lcmEgPT0gMTYpLCJDTFIgQWJ1bmRhbmNlIiwiIikpICsKICAgIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplPTcpLCB0aXRsZS5wb3NpdGlvbiA9ICdsZWZ0JywgbnJvdyA9IDEsIG5jb2wgPSA0KSkgKwogICAgdGhlbWUocGxvdC5tYXJnaW4gPSB1bml0KGMoMCwwLHBsb3RsaW1fbWFyZ2luLDApLCAiY20iKSwgCiAgICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9NS43NSksIAogICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MTApLCAKICAgICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xMCksIAogICAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT03KSwKICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemU9NyksIAogICAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemU9NyksCiAgICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBhc3BlY3QucmF0aW8gPSAwLjk1KQogIH0pCn0KCgpgYGAKCgpgYGB7cn0KbGlicmFyeShncGxvdHMpCmxpYnJhcnkoZ2dyZXBlbCkKbGlicmFyeShnZ2JyZWFrKQoKI1RydW5jYXRlIHRoZSB0b3AgMjAgaW5jbHVkaW5nIHZlcnVra2FtYW5zaWEgCnRpdGxlIDwtIGxpc3QoKQpmb3IoaSBpbiBzZXEoMToyMCkpIHsgdGl0bGVbaV0gPC0gbXlwbG90c1tbYyhpKV1dJGxhYmVscyR0aXRsZSB9CnBsb3RzMSA8LSBteXBsb3RzW3RpdGxlICVpbiUgcGFzdGUoCiAgc3BhbiRGYW1pbHksCiAgIlxuIiwKICBzcGFuJEdlbnVzLHNlcD0iIildWzE6MjBdCnBsb3RzX2ZpbmFsIDwtIHBsb3RzMVshc2FwcGx5KHBsb3RzMSxpcy5udWxsKV0KCmZpbmFsMSA8LSBnZ2FycmFuZ2UocGxvdGxpc3QgPSBwbG90c19maW5hbFsxOjVdLCBsYWJlbHMgPSBMRVRURVJTWzE6NV0sIGxlZ2VuZCA9ICJ0b3AiLCBhbGlnbiA9ICJodiIsIGZvbnQubGFiZWwgPSBsaXN0KHNpemUgPSA4KSwgY29tbW9uLmxlZ2VuZCA9IFRSVUUsIG5yb3cgPSAxLCBuY29sID0gNSkgKyB0aGVtZShwbG90Lm1hcmdpbiA9IHVuaXQoYygwLDAsMCwwKSwgImNtIikpCmZpbmFsMQpmaW5hbDIgPC0gZ2dhcnJhbmdlKHBsb3RsaXN0ID0gcGxvdHNfZmluYWxbNjoxMF0sIGxhYmVscyA9IExFVFRFUlNbNjoxMF0sIGxlZ2VuZCA9ICJ0b3AiLCBhbGlnbiA9ICJodiIsIGZvbnQubGFiZWwgPSBsaXN0KHNpemUgPSA4KSwgY29tbW9uLmxlZ2VuZCA9IFRSVUUsIG5yb3cgPSAxLCBuY29sID0gNSkgKyB0aGVtZShwbG90Lm1hcmdpbiA9IHVuaXQoYygwLDAsMCwwKSwgImNtIikpCmZpbmFsMgoKZmluYWwzIDwtIGdnYXJyYW5nZShwbG90bGlzdCA9IHBsb3RzX2ZpbmFsWzExOjE1XSwgbGFiZWxzID0gTEVUVEVSU1sxMToxNV0sIGxlZ2VuZCA9ICJ0b3AiLCBhbGlnbiA9ICJodiIsIGZvbnQubGFiZWwgPSBsaXN0KHNpemUgPSA4KSwgY29tbW9uLmxlZ2VuZCA9IFRSVUUsIG5yb3cgPSAxLCBuY29sID0gNSkgKyB0aGVtZShwbG90Lm1hcmdpbiA9IHVuaXQoYygwLDAsMCwwKSwgImNtIikpCmZpbmFsMwpmaW5hbDQgPC0gZ2dhcnJhbmdlKHBsb3RsaXN0ID0gcGxvdHNfZmluYWxbMTY6MjBdLCBsYWJlbHMgPSBMRVRURVJTWzE2OjIwXSwgbGVnZW5kID0gInRvcCIsIGFsaWduID0gImh2IiwgZm9udC5sYWJlbCA9IGxpc3Qoc2l6ZSA9IDgpLCBjb21tb24ubGVnZW5kID0gVFJVRSwgbnJvdyA9IDEsIG5jb2wgPSA1KSArIHRoZW1lKHBsb3QubWFyZ2luID0gdW5pdChjKDAsMCwwLDApLCAiY20iKSkKZmluYWw0Cgpjb3VudGVyPDwtMQpmaWd1cmVfbWFpbiA8LSBnZ2FycmFuZ2UocGxvdGxpc3QgPSBwbG90c19maW5hbFsxOjIwXSwgbGFiZWxzID0gTEVUVEVSU1sxOjIwXSwgbGVnZW5kID0gInRvcCIsIGFsaWduID0gImh2IiwgY29tbW9uLmxlZ2VuZCA9IFRSVUUsIG5yb3cgPSA0LCBuY29sID0gNSkKCmdnc2F2ZSgKICAiQk1GdnNHZW5lcmEyLnBuZyIsCiAgcGxvdCA9IGZpbmFsMSwKICBkZXZpY2UgPSBOVUxMLAogIHBhdGggPSBOVUxMLAogIHNjYWxlID0gMS41LAogIHdpZHRoID0gTkEsCiAgaGVpZ2h0ID0gTkEsCiAgdW5pdHMgPSBjKCJpbiIsICJjbSIsICJtbSIsICJweCIpLAogIGRwaSA9IDMwMCwKICBsaW1pdHNpemUgPSBUUlVFLAogIGJnID0gTlVMTAopCgpnZ3NhdmUoCiAgIkJNRnZzR2VuZXJhMy5wbmciLAogIHBsb3QgPSBmaW5hbDIsCiAgZGV2aWNlID0gTlVMTCwKICBwYXRoID0gTlVMTCwKICBzY2FsZSA9IDEuNSwKICB3aWR0aCA9IE5BLAogIGhlaWdodCA9IE5BLAogIHVuaXRzID0gYygiaW4iLCAiY20iLCAibW0iLCAicHgiKSwKICBkcGkgPSAzMDAsCiAgbGltaXRzaXplID0gVFJVRSwKICBiZyA9IE5VTEwKKQoKZ2dzYXZlKAogICJCTUZ2c0dlbmVyYTQucG5nIiwKICBwbG90ID0gZmluYWwzLAogIGRldmljZSA9IE5VTEwsCiAgcGF0aCA9IE5VTEwsCiAgc2NhbGUgPSAxLjUsCiAgd2lkdGggPSBOQSwKICBoZWlnaHQgPSBOQSwKICB1bml0cyA9IGMoImluIiwgImNtIiwgIm1tIiwgInB4IiksCiAgZHBpID0gMzAwLAogIGxpbWl0c2l6ZSA9IFRSVUUsCiAgYmcgPSBOVUxMCikKCmdnc2F2ZSgKICAiQk1GdnNHZW5lcmE1LnBuZyIsCiAgcGxvdCA9IGZpbmFsNCwKICBkZXZpY2UgPSBOVUxMLAogIHBhdGggPSBOVUxMLAogIHNjYWxlID0gMS41LAogIHdpZHRoID0gTkEsCiAgaGVpZ2h0ID0gTkEsCiAgdW5pdHMgPSBjKCJpbiIsICJjbSIsICJtbSIsICJweCIpLAogIGRwaSA9IDMwMCwKICBsaW1pdHNpemUgPSBUUlVFLAogIGJnID0gTlVMTAopCgpnZ3NhdmUoCiAgIkJNRnZzR2VuZXJhTWFpbi5wbmciLAogIHBsb3QgPSBmaW5hbF9tYWluLAogIGRldmljZSA9IE5VTEwsCiAgcGF0aCA9IE5VTEwsCiAgc2NhbGUgPSAxLjIsCiAgd2lkdGggPSBOQSwKICBoZWlnaHQgPSBOQSwKICB1bml0cyA9IGMoImluIiwgImNtIiwgIm1tIiwgInB4IiksCiAgZHBpID0gMzAwLAogIGxpbWl0c2l6ZSA9IFRSVUUsCiAgYmcgPSBOVUxMCikKCgoKYGBgCgoKCmBgYHtyfQpnZ3NhdmUoCiAgIkJNRnZzR2VuZXJhTWFpbi5wbmciLAogIHBsb3QgPSBmaW5hbF9tYWluLAogIGRldmljZSA9IE5VTEwsCiAgcGF0aCA9IE5VTEwsCiAgc2NhbGUgPSAwLjUsCiAgd2lkdGggPSBOQSwKICBoZWlnaHQgPSBOQSwKICB1bml0cyA9IGMoImluIiwgImNtIiwgIm1tIiwgInB4IiksCiAgZHBpID0gMzAwLAogIGxpbWl0c2l6ZSA9IFRSVUUsCiAgYmcgPSBOVUxMCikKYGBgCgoK